diff --git a/.clang-format-ignore b/.clang-format-ignore new file mode 100644 index 0000000000000..a6c57f5fb2ffb --- /dev/null +++ b/.clang-format-ignore @@ -0,0 +1 @@ +*.json diff --git a/.clang-tidy b/.clang-tidy index da768906bcc32..080c35ba31df3 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,3 +1,42 @@ +--- +Checks: + - -* + - modernize-avoid-bind + - modernize-deprecated-headers + - modernize-make-shared + - modernize-raw-string-literal + - modernize-redundant-void-arg + - modernize-replace-auto-ptr + - modernize-replace-random-shuffle + - modernize-shrink-to-fit + - modernize-unary-static-assert + - modernize-use-equals-default + - modernize-use-noexcept + - modernize-use-nullptr + - modernize-use-override + - modernize-use-transparent-functors + - modernize-use-uncaught-exceptions + - readability-braces-around-statements + - -clang-diagnostic-vla-cxx-extension CheckOptions: - - key: CheckPathRegex - value: '.*/O2/.*' + # Naming conventions + readability-identifier-naming.ClassCase: CamelCase + readability-identifier-naming.ClassMemberPrefix: m + readability-identifier-naming.ConceptCase: CamelCase + readability-identifier-naming.ConstexprVariableCase: CamelCase + readability-identifier-naming.EnumCase: CamelCase + readability-identifier-naming.EnumConstantCase: CamelCase + readability-identifier-naming.EnumConstantIgnoredRegexp: "^k?[A-Z][a-zA-Z0-9_]*$" # Allow "k" prefix and non-trailing underscores in PDG names. + readability-identifier-naming.FunctionCase: camelBack + readability-identifier-naming.MacroDefinitionCase: UPPER_CASE + readability-identifier-naming.MacroDefinitionIgnoredRegexp: "^[A-Z][A-Z0-9_]*_$" # Allow the trailing underscore in header guards. + readability-identifier-naming.MemberCase: camelBack + readability-identifier-naming.NamespaceCase: lower_case + readability-identifier-naming.ParameterCase: camelBack + readability-identifier-naming.StructCase: CamelCase + readability-identifier-naming.TemplateParameterCase: CamelCase + readability-identifier-naming.TypeAliasCase: CamelCase + readability-identifier-naming.TypedefCase: CamelCase + readability-identifier-naming.TypeTemplateParameterCase: CamelCase + readability-identifier-naming.VariableCase: camelBack +... diff --git a/.cmake-format.py b/.cmake-format.py index 9827eecd329c4..ae092bc09f363 100644 --- a/.cmake-format.py +++ b/.cmake-format.py @@ -66,12 +66,6 @@ "HEADERS": '*', } }, - "o2_target_man_page": { - "kwargs": { - "NAME": '+', - "SECTION": '*', - } - }, "add_root_dictionary": { "kwargs": { "LINKDEF": '+', diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000000..30ad6d8f005b3 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +--- +# Dependabot configuration +# Reference: https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "github-actions" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/workflows/async-list-label.yml b/.github/workflows/async-list-label.yml deleted file mode 100644 index e0b4185c563b7..0000000000000 --- a/.github/workflows/async-list-label.yml +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: Collect and print async labels - -'on': - pull_request_target: - types: - - opened - - reopened - branches: - - dev - -permissions: {} - -jobs: - list_async_labels: - name: Collect and print async labels - uses: alisw/ali-bot/.github/workflows/async-list-label.yml@master - permissions: - pull-requests: write # to update labels diff --git a/.github/workflows/clean-test.yml b/.github/workflows/clean-test.yml index 0f15301d4eed9..b149ae86b991d 100644 --- a/.github/workflows/clean-test.yml +++ b/.github/workflows/clean-test.yml @@ -19,10 +19,6 @@ name: Clean PR checks # Warning: the check_* keys are magic and must consist of the string # "check_" followed by the applicable check name exactly. The # "description" field is only the human-readable label for the input. - 'check_build/AliceO2/O2/o2/macOS': - description: build/AliceO2/O2/o2/macOS - type: boolean - default: true 'check_build/AliceO2/O2/o2/macOS-arm': description: build/AliceO2/O2/o2/macOS-arm type: boolean @@ -31,8 +27,8 @@ name: Clean PR checks description: build/O2/fullCI type: boolean default: true - 'check_build/O2/o2-dataflow-cs8': - description: build/O2/o2-dataflow-cs8 + 'check_build/O2/o2-dataflow-slc9': + description: build/O2/o2-dataflow-slc9 type: boolean default: true 'check_build/O2/o2/aarch64': diff --git a/.github/workflows/code-transformations.yml b/.github/workflows/code-transformations.yml index 4b5e55fcc2941..35493afda94f5 100644 --- a/.github/workflows/code-transformations.yml +++ b/.github/workflows/code-transformations.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false diff --git a/.github/workflows/datamodel-doc.yml b/.github/workflows/datamodel-doc.yml index 294fc2e50f50b..3ba015631aec6 100644 --- a/.github/workflows/datamodel-doc.yml +++ b/.github/workflows/datamodel-doc.yml @@ -10,20 +10,20 @@ jobs: steps: - name: Checkout O2 - uses: actions/checkout@v3 + uses: actions/checkout@v5 with: path: O2 persist-credentials: false - name: Checkout O2Physics - uses: actions/checkout@v3 + uses: actions/checkout@v5 with: repository: AliceO2Group/O2Physics path: O2Physics persist-credentials: false - name: Checkout documentation - uses: actions/checkout@v3 + uses: actions/checkout@v5 with: repository: AliceO2Group/analysis-framework path: analysis-framework @@ -40,7 +40,7 @@ jobs: git checkout -B auto-datamodel-doc - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v6 with: python-version: 3.x diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index 38da67c793799..b1dbaf122b342 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -13,7 +13,7 @@ jobs: run: | sudo apt-get update -y sudo apt-get install -y doxygen doxygen-doc doxygen-latex doxygen-gui graphviz cmake - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 with: ref: "dev" persist-credentials: false diff --git a/.github/workflows/first-timer.yml b/.github/workflows/first-timer.yml index 20b7ee6a070a8..54334d109bd49 100644 --- a/.github/workflows/first-timer.yml +++ b/.github/workflows/first-timer.yml @@ -8,7 +8,7 @@ jobs: nag_first_timer: runs-on: ubuntu-latest steps: - - uses: actions/first-interaction@v1 + - uses: actions/first-interaction@v3 with: repo-token: ${{ secrets.GITHUB_TOKEN }} pr-message: 'This seems to be your first PR. You will need a positive review in order for tests to start.' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 894ff2e0bb49b..2f692527ea5ce 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: branch=$(echo ${{ github.event.inputs.tag }}-patches | tr . - | sed -e's/-[0-9]*-patches$/-patches/') EOF id: decide_release_branch - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 with: ref: "dev" - name: Tag branch (or create one before tagging if does not exists) diff --git a/.github/workflows/reports.yml b/.github/workflows/reports.yml index cadb920fa022f..5a04e56382fb3 100644 --- a/.github/workflows/reports.yml +++ b/.github/workflows/reports.yml @@ -17,12 +17,12 @@ jobs: if: github.repository == 'AliceO2Group/AliceO2' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Set up Python 3.10 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: '3.10' - - uses: actions/cache@v4 + - uses: actions/cache@v5 name: Configure pip caching with: path: ~/.cache/pip diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 1f1387d4868ae..23f454aaca950 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -7,7 +7,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v1 + - uses: actions/stale@v10 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-pr-message: 'This PR did not have any update in the last 30 days. Is it still needed? Unless further action in will be closed in 5 days.' diff --git a/.gitignore b/.gitignore index 6db76441528d9..d58d1e151800b 100644 --- a/.gitignore +++ b/.gitignore @@ -82,6 +82,9 @@ bazel-* # direnv .envrc +# git wrappers +.sl + # LSP support on macOS with vim .clangd DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h diff --git a/.skills/build-software-stack/SKILL.md b/.skills/build-software-stack/SKILL.md new file mode 100644 index 0000000000000..8b137891791fe --- /dev/null +++ b/.skills/build-software-stack/SKILL.md @@ -0,0 +1 @@ + diff --git a/.skills/create-a-new-file/SKILL.md b/.skills/create-a-new-file/SKILL.md new file mode 100644 index 0000000000000..a7af739d49894 --- /dev/null +++ b/.skills/create-a-new-file/SKILL.md @@ -0,0 +1,20 @@ +--- +name: create-a-new-file +description: describes how to create a new file +--- + +## Copyright statements + +The copyright statement for ALICE / O2 is found in ./o2-copyright-statement.md. It should be at the beginning of +the new file using the proper commenting syntax for the given programming language. For example in C++ it should be commented via +multiline comments: + +``` C++ +// Copyright 2019- CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// ... +``` + +The only part which needs to be adapted by you is the `` which you need to replace with the actual current year. + + diff --git a/Framework/TestWorkflows/src/dummy.cxx b/.skills/create-a-new-file/o2-copyright-statement.md similarity index 86% rename from Framework/TestWorkflows/src/dummy.cxx rename to .skills/create-a-new-file/o2-copyright-statement.md index faff430964e73..0bc4b092e6ba6 100644 --- a/Framework/TestWorkflows/src/dummy.cxx +++ b/.skills/create-a-new-file/o2-copyright-statement.md @@ -1,4 +1,4 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// Copyright 2019- CERN and copyright holders of ALICE O2. // See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. // All rights not expressly granted are reserved. // @@ -8,3 +8,4 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. + diff --git a/Algorithm/CMakeLists.txt b/Algorithm/CMakeLists.txt index b245562c7cc93..ed7a42a96e528 100644 --- a/Algorithm/CMakeLists.txt +++ b/Algorithm/CMakeLists.txt @@ -11,9 +11,6 @@ o2_add_header_only_library(Algorithm INTERFACE_LINK_LIBRARIES O2::Headers) -o2_target_man_page(Algorithm NAME Algorithm SECTION 3) -o2_target_man_page(Algorithm NAME algorithm_parser SECTION 3) - o2_add_test(o2formatparser SOURCES test/o2formatparser.cxx COMPONENT_NAME Algorithm diff --git a/Algorithm/doc/Algorithm.3.in b/Algorithm/doc/Algorithm.3.in deleted file mode 100644 index eaf618ee68da2..0000000000000 --- a/Algorithm/doc/Algorithm.3.in +++ /dev/null @@ -1,12 +0,0 @@ -.\" Alice O2 manpage for module Algorithm -.TH "AliceO2" 3 "17 Jan 2017" "1.0" "Algorithm man page" - -.SH NAME -AliceO2 - module -.B Algorithm - -.SH DESCRIPTION -A collection of generic algorithms for Alice O2 - -.SH SEE ALSO -algorithm_parser(3) diff --git a/Algorithm/doc/algorithm_parser.3.in b/Algorithm/doc/algorithm_parser.3.in deleted file mode 100644 index 98f45df279669..0000000000000 --- a/Algorithm/doc/algorithm_parser.3.in +++ /dev/null @@ -1,135 +0,0 @@ -.\" Alice O2 manpage for parser algorithms -.TH "AliceO2" 3 "17 Jan 2017" "1.0" "Algorithm Parser man page" - -.SH NAME -AliceO2 - module -.B Algorithm -- data parsers - -.SH SYNOPSIS -.B ForwardParser< -.I SomeHeaderType -, -.I SomeTrailerType -.B > - -.B ReverseParser< -.I SomeHeaderType -, -.I SomeTrailerType -.B > - -.SS Public types -.TP 2 -// a compound of header, data, and trailer -.B struct FrameInfo { - using PtrT = const PayloadType*; - const HeaderType* header = nullptr; - const TrailerType* trailer = nullptr; - PtrT payload = nullptr; - size_t length = 0; - -.B }; - -.TP 2 -.B using CheckHeaderFct = std::function; -alias for callback checking the header, return true if the object is a valid header -.TP 2 -.B using CheckTrailerFct = std::function; -alias for callback checking the trailer -.TP 2 -.B using GetFrameSizeFct = std::function; -alias for callback to get the complete frame size including header, trailer and the data -.TP 2 -.B using InsertFct = std::function; -function callback to insert/handle one frame into, sequentially called for all frames if the whole block has a valid format - -.SS Public member functions -.TP 2 -.B template -.B int parse(const InputType* \fIbuffer\fB, size_t \fIbufferSize\fB, CheckHeaderFct \fIcheckHeader\fB, CheckTrailerFct \fIcheckTrailer\fB, GetFrameSizeFct \fIgetFrameSize\fB, InsertFct \fIinsert\fB) - -.SS Public member variables -.TP 2 -.B static const size_t headOffset = typesize::size; -the length offset due to header -.TP 2 -.B static const size_t tailOffset = typesize::size; -the length offset due to trailer -.TP 2 -.B static const size_t totalOffset = headOffset + tailOffset; -total length offset due to header and trailer - -.SH DESCRIPTION -Template utilities for parsing of data sequences. Each entry in the sequence consist of a header, variable payload, and optionally a trailer. The three parts are collected in the FrameInfo structure for every entry. - -Callback functions for checking header and trailer integrity, getting length of the current frame and handling of a frame. - -.SS ForwardParser -The size is expected to be part of the header, parsing starts at beginning of buffer. -Trailer type can be void, which is also the default template parameter. That -allows to define a frame consisting of only header and data. - -.SS ReverseParser -The size is expected to be part of the trailer, the parsing is thus in reverse direction. Also the insert callback is called with the entries starting form the end of the buffer. -An easy extension can be to reverse the order of the inserts, meaning that the entries are read from the beginning. - -.SH EXAMPLES -.SS ReverseParser example -.EX -using SomeParser = ReverseParser; -SomeParser parser; -std::vector frames; -parser.parse(ptr, size, - [] (const typename SomeParser::HeaderType& h) { - // check the header - return true; - }, - [] (const typename SomeParser::TrailerType& t) { - // check the trailer - return true; - }, - [] (const typename SomeParser::TrailerType& t) { - // get the size of the frame including payload - // and header and trailer size, e.g. payload size - // from a trailer member - return t.payloadSize + SomeParser::totalOffset; - }, - [&frames] (typename SomeParser::FrameInfo& info) { - frames.emplace_back(info); - return true; - } - ) -.EE - -.SS ForwardParser example with frame consisting of header and payload -.EX -using SomeParser = ForwardParser; -SomeParser parser; -std::vector frames; -parser.parse(ptr, size, - [] (const typename SomeParser::HeaderType& h) { - // check the header - return true; - }, - [] (const typename SomeParser::HeaderType& h) { - // get the size of the frame including payload - // and header and trailer size, e.g. payload size - // from a header member - return h.payloadSize + SomeParser::totalOffset; - }, - [&frames] (typename SomeParser::FrameInfo& info) { - frames.emplace_back(info); - return true; - } - ) -.EE - -.SH BUGS, CONTRIBUTIONS -Please add an issue to -.UR https://github.com/AliceO2Group/AliceO2/issues -.UE - -.SH SEE ALSO -.UR https://github.com/AliceO2Group/AliceO2/blob/dev/Algorithm/include/Algorithm/Parser.h -.UE diff --git a/Algorithm/include/Algorithm/BitstreamReader.h b/Algorithm/include/Algorithm/BitstreamReader.h deleted file mode 100644 index 0a112183ab5ef..0000000000000 --- a/Algorithm/include/Algorithm/BitstreamReader.h +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef BITSTREAMREADER_H -#define BITSTREAMREADER_H - -/// @file BitstreamReader.h -/// @author Matthias Richter -/// @since 2019-06-05 -/// @brief Utility class to provide bitstream access to an underlying resource - -#include -#include - -namespace o2 -{ -namespace algorithm -{ - -/// @class BitStreamReader -/// @brief Utility class to provide bitstream access to an underlying resource -/// -/// Allows to access bits of variable length, supports integral types and also -/// bitsets as target type. At the moment, the access is in direction MSB -> LSB. -/// -/// BitstreamReader reader(start, end); -/// while (reader.good() && not reader.eof()) { -/// // get an 8 bit value from the stream, moves the position -/// uint8_t ivalue; -/// reader.get(ivalue); -/// -/// // get a 13 bit bitset without moving the position -/// std::bitset<13> value; -/// reader.peek(value, value.size()); -/// // e.g. use 7 bits of the data -/// value >>= value.size() - 7; -/// // move position by the specific number of bits -/// reader.seek(7); -/// } -template -class BitstreamReader -{ - public: - using self_type = BitstreamReader; - // for the moment we simply use pointers, but with some traits this can be extended to - // containers - using value_type = BufferType; - using iterator = const value_type*; - static constexpr size_t value_size = sizeof(value_type) * 8; - BitstreamReader() = delete; - BitstreamReader(iterator start, iterator end) - : mStart(start), mEnd(end), mCurrent(mStart), mBitPosition(value_size) - { - } - ~BitstreamReader() = default; - - /// Check reader's state - /// @return true if not in error state - bool good() const - { - return mBitPosition > 0; - } - - /// Indicates end of data - /// @return true if end of resource is reached - bool eof() const - { - return mCurrent == mEnd && mBitPosition > 0; - } - - /// Reset the reader, start over at beginning - void reset() - { - mCurrent = mStart; - mBitPosition = value_size; - } - - /// Get the next N bits without moving the read position - /// if bitlength is smaller than the size of data type, result is aligned to LSB - /// TODO: this also works nicely for bitsets, but then the bitlength has to be specified - /// as template parameter, want to do a specific overload, but needs more work to catch - /// all cases. - /// @param v target variable passed by reference - /// @return number of poked bits - template - size_t peek(T& v) - { - static_assert(N <= sizeof(T) * 8); - return peek(v, N); - } - - /// Get the next n bits without moving the read position - /// if bitlength is smaller than the size of data type, result is aligned to LSB - /// @param v target variable passed by reference - /// @param bitlength number of bits to read - /// @return number of poked bits - template - size_t peek(T& v, size_t bitlength) - { - return peek(v, bitlength); - } - - /// Move read position - /// @param bitlength move count in number of bits - void seek(size_t bitlength) - { - while (good() && bitlength > 0 && mCurrent != mEnd) { - if (bitlength >= mBitPosition) { - bitlength -= mBitPosition; - mBitPosition = 0; - } else { - mBitPosition -= bitlength; - bitlength = 0; - } - if (mBitPosition == 0) { - mCurrent++; - mBitPosition = value_size; - } - } - - if (bitlength > 0) { - mBitPosition = 0; - } - } - - /// Get the next n bits and move the read position - template - T get() - { - T result; - peek(result); - seek(N); - return result; - } - - /// Get the next n and move the read position - template - T get(size_t bitlength = sizeof(T) * 8) - { - T result; - peek(result, bitlength); - seek(bitlength); - return result; - } - - /// @class Bits - /// @brief Helper class to get value of specified type which holds the number used bits - /// - /// The class holds both the extracted value access via peek method and the number of used - /// bits. The reader will be incremented when the object is destroyed. - /// The number of bits can be adjusted by using markUsed method - template - class Bits - { - public: - using field_type = FieldType; - static_assert(N <= sizeof(FieldType) * 8); - Bits() - : mParent(nullptr), mData(0), mLength(0) - { - } - Bits(ParentType* parent, FieldType&& data) - : mParent(parent), mData(std::move(data)), mLength(N) - { - } - Bits(Bits&& other) - : mParent(other.mParent), mData(std::move(other.mData)), mLength(other.mLength) - { - other.mParent = nullptr; - other.mLength = 0; - } - - ~Bits() - { - if (mParent) { - mParent->seek(mLength); - } - } - - auto& operator=(Bits&& other) - { - mParent = other.mParent; - mData = std::move(other.mData); - mLength = other.mLength; - other.mParent = nullptr; - other.mLength = 0; - - return *this; - } - - FieldType& operator*() - { - return mData; - } - - void markUsed(size_t length) - { - mLength = length; - } - - private: - ParentType* mParent; - FieldType mData; - size_t mLength; - }; - - /// Read an integral value from the stream - template ::value, int> = 0> - self_type& operator>>(T& target) - { - target = get(); - return *this; - } - - /// Read a bitstream value from the stream - template - self_type& operator>>(std::bitset& target) - { - target = get, N>(); - return *this; - } - - /// Read a Bits object from the stream - template - self_type& operator>>(Bits& target) - { - T bitfield; - peek(bitfield); - target = std::move(Bits(this, std::move(bitfield))); - return *this; - } - - private: - /// The internal peek method - template - size_t peek(T& result, size_t bitlength) - { - if constexpr (RuntimeCheck) { - // the runtime check is disabled if bitlength is derived at compile time - if (bitlength > sizeof(T) * 8) { - throw std::length_error(std::string("requested bit length ") + std::to_string(bitlength) + " does not fit size of result data type " + std::to_string(sizeof(T) * 8)); - } - } - result = 0; - size_t bitsToWrite = bitlength; - auto current = mCurrent; - auto bitsAvailable = mBitPosition; - while (bitsToWrite > 0 && current != mEnd) { - // extract available bits - value_type mask = ~value_type(0) >> (value_size - bitsAvailable); - if (bitsToWrite >= bitsAvailable) { - T value = (*current & mask) << (bitsToWrite - bitsAvailable); - result |= value; - bitsToWrite -= bitsAvailable; - bitsAvailable = 0; - } else { - value_type value = (*current & mask) >> (bitsAvailable - bitsToWrite); - result |= value; - bitsAvailable -= bitsToWrite; - bitsToWrite = 0; - } - if (bitsAvailable == 0) { - current++; - bitsAvailable = value_size; - } - } - - return bitlength - bitsToWrite; - } - - /// start of resource - iterator mStart; - /// end of resource - iterator mEnd; - /// current position in resource - iterator mCurrent; - /// bit position in current element - size_t mBitPosition; -}; -} // namespace algorithm -} // namespace o2 -#endif diff --git a/Algorithm/test/test_BitstreamReader.cxx b/Algorithm/test/test_BitstreamReader.cxx deleted file mode 100644 index 41e3b47f5f276..0000000000000 --- a/Algorithm/test/test_BitstreamReader.cxx +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file test_BitstreamReader.cxx -/// @author Matthias Richter -/// @since 2019-06-05 -/// @brief Test program for BitstreamReader utility - -#define BOOST_TEST_MODULE Algorithm BitstreamReader unit test -#define BOOST_TEST_MAIN -#define BOOST_TEST_DYN_LINK -#include -#include -#include -#include -#include -#include -#include "../include/Algorithm/BitstreamReader.h" - -namespace o2 -{ -namespace algorithm -{ - -BOOST_AUTO_TEST_CASE(test_BitstreamReader_basic) -{ - std::array data = {'d', 'e', 'a', 'd', 'b', 'e', 'e', 'f'}; - std::array expected7bit = {0x32, 0x19, 0x2c, 0x16, 0x23, 0x09, 0x4a, 0x65, 0x33, 0x0}; - auto reference = expected7bit.begin(); - constexpr size_t totalBits = data.size() * sizeof(decltype(data)::value_type) * 8; - size_t bitsRead = 0; - - BitstreamReader reader(data.data(), data.data() + data.size()); - while (bitsRead < totalBits) { - BOOST_REQUIRE(reference != expected7bit.end()); - BOOST_CHECK(reader.eof() == false); - uint8_t value; - reader.peek(value); - // we use 7 bits of the data - value >>= 1; - reader.seek(7); - bitsRead += 7; - // in the last call should there is not enough data - BOOST_CHECK(reader.good() == (bitsRead <= totalBits)); - BOOST_REQUIRE(reference != expected7bit.end()); - //std::cout << "value " << (int)value << " expected " << (int)*reference << std::endl; - BOOST_CHECK(value == *reference); - ++reference; - } -} - -BOOST_AUTO_TEST_CASE(test_BitstreamReader_operator) -{ - std::array data = {'d', 'e', 'a', 'd', 'b', 'e', 'e', 'f'}; - std::array expected7bit = {0x32, 0x19, 0x2c, 0x16, 0x23, 0x09, 0x4a, 0x65, 0x33, 0x0}; - auto reference = expected7bit.begin(); - constexpr size_t totalBits = data.size() * sizeof(decltype(data)::value_type) * 8; - size_t bitsRead = 0; - - BitstreamReader reader(data.data(), data.data() + data.size()); - while (bitsRead < totalBits) { - BOOST_REQUIRE(reference != expected7bit.end()); - BOOST_CHECK(reader.eof() == false); - { - decltype(reader)::Bits value; - reader >> value; - // we use 7 bits of the data - *value >>= 1; - value.markUsed(7); - //std::cout << "value " << (int)*value << " expected " << (int)*reference << std::endl; - BOOST_CHECK(*value == *reference); - } - bitsRead += 7; - // in the last call should there is not enough data - BOOST_CHECK(reader.good() == (bitsRead <= totalBits)); - BOOST_REQUIRE(reference != expected7bit.end()); - ++reference; - } -} - -BOOST_AUTO_TEST_CASE(test_BitstreamReader_bitset) -{ - std::array data = {'d', 'e', 'a', 'd', 'b', 'e', 'e', 'f'}; - std::array expected7bit = {0x32, 0x19, 0x2c, 0x16, 0x23, 0x09, 0x4a, 0x65, 0x33, 0x0}; - auto reference = expected7bit.begin(); - constexpr size_t totalBits = data.size() * sizeof(decltype(data)::value_type) * 8; - size_t bitsRead = 0; - - BitstreamReader reader(data.data(), data.data() + data.size()); - while (bitsRead < totalBits) { - BOOST_REQUIRE(reference != expected7bit.end()); - BOOST_CHECK(reader.eof() == false); - std::bitset<13> value; - reader.peek(value, value.size()); - // we use 7 bits of the data - value >>= value.size() - 7; - reader.seek(7); - bitsRead += 7; - // in the last call should there is not enough data - BOOST_CHECK(reader.good() == (bitsRead <= totalBits)); - BOOST_REQUIRE(reference != expected7bit.end()); - BOOST_CHECK_MESSAGE(value.to_ulong() == *reference, std::string("mismatch: value ") << value.to_ulong() << ", expected " << (int)*reference); - ++reference; - } - - reader.reset(); - std::bitset<16> aBitset; - reader >> aBitset; - BOOST_CHECK_MESSAGE(aBitset.to_ulong() == 0x6465, std::string("mismatch: value 0x") << std::hex << aBitset.to_ulong() << ", expected 0x6465"); -} - -} // namespace algorithm -} // namespace o2 diff --git a/CCDB/CMakeLists.txt b/CCDB/CMakeLists.txt index 9436fa37de8e6..691c3311e117c 100644 --- a/CCDB/CMakeLists.txt +++ b/CCDB/CMakeLists.txt @@ -92,6 +92,12 @@ o2_add_test(CcdbDownloader PUBLIC_LINK_LIBRARIES O2::CCDB LABELS ccdb) +o2_add_test(CcdbApi-Headers + SOURCES test/testCcdbApiHeaders.cxx + COMPONENT_NAME ccdb + PUBLIC_LINK_LIBRARIES O2::CCDB + LABELS ccdb) + # extra CcdbApi test which dispatches to CCDBDownloader (tmp until full move done) #o2_add_test_command(NAME CcdbApi-MultiHandle # WORKING_DIRECTORY ${SIMTESTDIR} diff --git a/CCDB/README.md b/CCDB/README.md index ce8d9e19f7b27..1ae5f29dcf0e2 100644 --- a/CCDB/README.md +++ b/CCDB/README.md @@ -13,7 +13,7 @@ in circumstances of reduced or no network connectivity. There are currently 2 different kinds of store/retrieve functions, which we expect to unify in the immediate future: 2. `storeAsTFile/retrieveFromTFile` API serializing a `TObject` in a ROOT `TFile`. -3. A strongly-typed `storeAsTFileAny/retrieveFromTFileAny` API allowing to handle any type T +3. A strongly-typed `storeAsTFileAny/retrieveFromTFileAny` API allowing to handle any type T having a ROOT dictionary. We encourage to use this API by default. ## Central and local instances of the CCDB @@ -31,18 +31,18 @@ If you access the CCDB with a web browser, add `/browse` at the end of the URL t ```c++ // init CcdbApi api; -map metadata; // can be empty +std::map 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 auto deadpixels = new o2::FOO::DeadPixelMap(); api.storeAsTFileAny(deadpixels, "FOO/DeadPixels", metadata); // read like this (you have to specify the type) -auto deadpixelsback = api.retrieveFromTFileAny("FOO/DeadPixels", metadata); -// read like this to get the headers as well, and thus the metadata attached to the object -map headers; -auto deadpixelsback = api.retrieveFromTFileAny("FOO/DeadPixels", metadata /* constraint the objects retrieved to those matching the metadata */, -1 /* timestamp */, &headers /* the headers attached to the returned object */); +auto deadpixelsback = api.retrieveFromTFileAny("FOO/DeadPixels", metadata); +// read like this to get the headers as well, and thus the metadata attached to the object +std::map headers; +auto deadpixelsback = api.retrieveFromTFileAny("FOO/DeadPixels", metadata /* constraint the objects retrieved to those matching the metadata */, -1 /* timestamp */, &headers /* the headers attached to the returned object */); // finally, use this method to retrieve only the headers (and thus the metadata) -std::map headers = f.api.retrieveHeaders("FOO/DeadPixels", f.metadata); +std::map headers = api.retrieveHeaders("FOO/DeadPixels", metadata); ``` * creating a local snapshot and fetching objects therefrom @@ -50,7 +50,7 @@ std::map headers = f.api.retrieveHeaders("FOO/DeadPixe ```c++ // init CcdbApi api; -map metadata; // can be empty +std::map metadata; // can be empty api.init("http://ccdb-test.cern.ch:8080"); // or http://localhost:8080 for a local installation // create a local snapshot of everthing in or below the FOO folder valid for timestamp 12345 api.snapshot("FOO", "/tmp/CCDBSnapshot/", 12345); @@ -85,7 +85,7 @@ user code. This class The class was written for the use-case of transport MC simulation. Typical usage should be like ```c++ -// setup manager once (at start of processing) +// setup manager once (at start of processing) auto& mgr = o2::ccdb::BasicCCDBManager::instance(); mgr.setURL("http://ourccdbserverver.cern.ch"); mgr.setTimestamp(timestamp_which_we_want_to_anchor_to); @@ -111,6 +111,12 @@ This feature is useful to avoid using newer objects if the CCDB is updated in pa In cached mode, the manager can check that local objects are still valid by requiring `mgr.setLocalObjectValidityChecking(true)`, in this case a CCDB query is performed only if the cached object is no longer valid. +If you want the headers/metadata for the object retrieved from the CCDB there is an optional paramater to `BasicCCDBManager::getForTimeStamp`. These headers are also cached (when caching is enabled) and is updated when a CCDB query is sent. +```c++ +std::map headers; +mgr.getForTimeStamp(path, timstamp, metadata, &headers); +``` + ## Future ideas / todo: - [ ] offer improved error handling / exceptions @@ -129,26 +135,26 @@ A few prototypic command line tools are offered. These can be used in scriptable and facilitate the following tasks: 1. Upload and annotate a generic C++ object serialized in a ROOT file - + ```bash o2-ccdb-upload -f myRootFile.root --key histogram1 --path /Detector1/QA/ --meta "Description=Foo;Author=Person1;Uploader=Person2" ``` This will upload the object serialized in `myRootFile.root` under the key `histogram1`. Object will be put to the CCDB path `/Detector1/QA`. For full list of options see `o2-ccdb-upload --help`. - + 2. Download a CCDB object to a local ROOT file (including its meta information) - + ```bash o2-ccdb-downloadccdbfile --path /Detector1/QA/ --dest /tmp/CCDB --timestamp xxx ``` This will download the CCDB object under path given by `--path` to a directory given by `--dest` on the disc. (The final filename will be `/tmp/CCDB/Detector1/QA/snapshot.root` for the moment). All meta-information as well as the information associated to this query will be appended to the file. - + For full list of options see `o2-ccdb-downloadccdbfile --help`. - + 3. Inspect the content of a ROOT file and print summary about type of contained (CCDB) objects and its meta information - + ```bash o2-ccdb-inspectccdbfile filename ``` diff --git a/CCDB/include/CCDB/BasicCCDBManager.h b/CCDB/include/CCDB/BasicCCDBManager.h index b7bf6920a5c7c..6ad645a0a893e 100644 --- a/CCDB/include/CCDB/BasicCCDBManager.h +++ b/CCDB/include/CCDB/BasicCCDBManager.h @@ -20,9 +20,12 @@ #include "CommonUtils/NameConf.h" #include "Framework/DataTakingContext.h" #include "Framework/DefaultsHelpers.h" +#include "Framework/ServiceRegistryRef.h" +#include "Framework/DataProcessingStats.h" #include #include #include +#include #include #include #include @@ -52,16 +55,18 @@ class CCDBManagerInstance long endvalidity = -1; long cacheValidFrom = 0; // time for which the object was cached long cacheValidUntil = -1; // object is guaranteed to be valid till this time (modulo new updates) + size_t size = 0; size_t minSize = -1ULL; size_t maxSize = 0; int queries = 0; int fetches = 0; int failures = 0; + std::map cacheOfHeaders; bool isValid(long ts) { return ts < endvalidity && ts >= startvalidity; } bool isCacheValid(long ts) { - LOGP(debug, "isCacheValid : {} : {} : {} --> {}", cacheValidFrom, ts, cacheValidUntil, ts < cacheValidUntil && ts >= cacheValidFrom); - return ts < cacheValidUntil && ts >= cacheValidFrom; + LOGP(debug, "isCacheValid : {} : {} : {} --> {}", cacheValidFrom, ts, cacheValidUntil, isValid(ts)); + return ts < cacheValidUntil && isValid(ts); } void clear() { @@ -70,6 +75,7 @@ class CCDBManagerInstance uuid = ""; startvalidity = 0; endvalidity = -1; + cacheOfHeaders.clear(); } }; @@ -98,9 +104,9 @@ class CCDBManagerInstance /// query timestamp long getTimestamp() const { return mTimestamp; } - /// retrieve an object of type T from CCDB as stored under path and timestamp + /// retrieve an object of type T from CCDB as stored under path and timestamp. Optional to get the headers. template - T* getForTimeStamp(std::string const& path, long timestamp); + T* getForTimeStamp(std::string const& path, long timestamp, std::map* headers = nullptr); /// retrieve an object of type T from CCDB as stored under path and using the timestamp in the middle of the run template @@ -108,16 +114,17 @@ class CCDBManagerInstance /// retrieve an object of type T from CCDB as stored under path, timestamp and metaData template - T* getSpecific(std::string const& path, long timestamp = -1, MD metaData = MD()) + T* getSpecific(std::string const& path, long timestamp = -1, MD metaData = MD(), std::map* headers = nullptr) { // TODO: add some error info/handling when failing mMetaData = metaData; - return getForTimeStamp(path, timestamp); + auto obj = getForTimeStamp(path, timestamp, headers); + return obj; } /// retrieve an object of type T from CCDB as stored under path and using the timestamp in the middle of the run + metadata. The run number is provided separately to conform to typical analysis use (in which case metadata does not include runNumber) template - T* getSpecificForRun(std::string const& path, int runNumber, MD metaData = MD()); + T* getSpecificForRun(std::string const& path, int runNumber, MD const& metaData = MD()); /// detect online processing modes (i.e. CCDB objects may be updated in the lifetime of the manager) bool isOnline() const { return mDeplMode == o2::framework::DeploymentMode::OnlineAUX || mDeplMode == o2::framework::DeploymentMode::OnlineDDS || mDeplMode == o2::framework::DeploymentMode::OnlineECS; } @@ -129,6 +136,9 @@ class CCDBManagerInstance return getForTimeStamp(path, mTimestamp); } + // gain access to underlaying CCDB layer (to allow for more complex queries without need to reinit another API) + CcdbApi& getCCDBAccessor() { return mCCDBAccessor; } + bool isHostReachable() const { return mCCDBAccessor.isHostReachable(); } /// clear all entries in the cache @@ -220,6 +230,7 @@ class CCDBManagerInstance long mCreatedNotBefore = 0; // lower limit for object creation timestamp (TimeMachine mode) - If-Not-Before HTTP header long mTimerMS = 0; // timer for queries size_t mFetchedSize = 0; // total fetched size + size_t mRequestedSize = 0; // total requested size (fetched + served from cache) int mQueries = 0; // total number of object queries int mFetches = 0; // total number of succesful fetches from CCDB int mFailures = 0; // total number of failed fetches @@ -228,13 +239,14 @@ class CCDBManagerInstance }; template -T* CCDBManagerInstance::getForTimeStamp(std::string const& path, long timestamp) +T* CCDBManagerInstance::getForTimeStamp(std::string const& path, long timestamp, std::map* headers) { + mHeaders.clear(); // we clear at the beginning; to allow to retrieve the header information in a subsequent call T* ptr = nullptr; mQueries++; auto start = std::chrono::system_clock::now(); if (!isCachingEnabled()) { - ptr = mCCDBAccessor.retrieveFromTFileAny(path, mMetaData, timestamp, nullptr, "", + ptr = mCCDBAccessor.retrieveFromTFileAny(path, mMetaData, timestamp, &mHeaders, "", mCreatedNotAfter ? std::to_string(mCreatedNotAfter) : "", mCreatedNotBefore ? std::to_string(mCreatedNotBefore) : ""); if (!ptr) { @@ -248,17 +260,36 @@ T* CCDBManagerInstance::getForTimeStamp(std::string const& path, long timestamp) if (sh != mHeaders.end()) { size_t s = atol(sh->second.c_str()); mFetchedSize += s; + mRequestedSize += s; } } + + if (headers) { + *headers = mHeaders; + } } else { auto& cached = mCache[path]; cached.queries++; if ((!isOnline() && cached.isCacheValid(timestamp)) || (mCheckObjValidityEnabled && cached.isValid(timestamp))) { + // Give back the cached/saved headers + if (headers) { + *headers = cached.cacheOfHeaders; + } + mRequestedSize += cached.size; return reinterpret_cast(cached.noCleanupPtr ? cached.noCleanupPtr : cached.objPtr.get()); } ptr = mCCDBAccessor.retrieveFromTFileAny(path, mMetaData, timestamp, &mHeaders, cached.uuid, mCreatedNotAfter ? std::to_string(mCreatedNotAfter) : "", mCreatedNotBefore ? std::to_string(mCreatedNotBefore) : ""); + // update the cached headers + for (auto const& h : mHeaders) { + cached.cacheOfHeaders[h.first] = h.second; + } + // return the cached headers + if (headers) { + *headers = cached.cacheOfHeaders; + } + if (ptr) { // new object was shipped, old one (if any) is not valid anymore cached.fetches++; mFetches++; @@ -291,6 +322,8 @@ T* CCDBManagerInstance::getForTimeStamp(std::string const& path, long timestamp) if (sh != mHeaders.end()) { size_t s = atol(sh->second.c_str()); mFetchedSize += s; + mRequestedSize += s; + cached.size = s; cached.minSize = std::min(s, cached.minSize); cached.maxSize = std::max(s, cached.minSize); } @@ -305,7 +338,6 @@ T* CCDBManagerInstance::getForTimeStamp(std::string const& path, long timestamp) } else { cached.cacheValidUntil = -1; } - mHeaders.clear(); mMetaData.clear(); if (!ptr) { if (mFatalWhenNull) { @@ -316,6 +348,15 @@ T* CCDBManagerInstance::getForTimeStamp(std::string const& path, long timestamp) } auto end = std::chrono::system_clock::now(); mTimerMS += std::chrono::duration_cast(end - start).count(); + auto* ref = o2::framework::ServiceRegistryRef::globalDeviceRef(); + if (ref && ref->active()) { + auto& stats = ref->get(); + stats.updateStats({(int)o2::framework::ProcessingStatsId::CCDB_CACHE_HIT, o2::framework::DataProcessingStats::Op::Set, (int64_t)mQueries - mFailures - mFetches}); + stats.updateStats({(int)o2::framework::ProcessingStatsId::CCDB_CACHE_MISS, o2::framework::DataProcessingStats::Op::Set, (int64_t)mFetches}); + stats.updateStats({(int)o2::framework::ProcessingStatsId::CCDB_CACHE_FAILURE, o2::framework::DataProcessingStats::Op::Set, (int64_t)mFailures}); + stats.updateStats({(int)o2::framework::ProcessingStatsId::CCDB_CACHE_FETCHED_BYTES, o2::framework::DataProcessingStats::Op::Set, (int64_t)mFetchedSize}); + stats.updateStats({(int)o2::framework::ProcessingStatsId::CCDB_CACHE_REQUESTED_BYTES, o2::framework::DataProcessingStats::Op::Set, (int64_t)mRequestedSize}); + } return ptr; } @@ -328,7 +369,7 @@ T* CCDBManagerInstance::getForRun(std::string const& path, int runNumber, bool s } template -T* CCDBManagerInstance::getSpecificForRun(std::string const& path, int runNumber, MD metaData) +T* CCDBManagerInstance::getSpecificForRun(std::string const& path, int runNumber, MD const& metaData) { auto [start, stop] = getRunDuration(runNumber, mFatalWhenNull); if (start < 0 || stop < 0) { @@ -367,4 +408,4 @@ class BasicCCDBManager : public CCDBManagerInstance } // namespace o2::ccdb -#endif //O2_BASICCCDBMANAGER_H +#endif // O2_BASICCCDBMANAGER_H diff --git a/CCDB/include/CCDB/CcdbApi.h b/CCDB/include/CCDB/CcdbApi.h index 1308742b57fd0..4dab11d5972d8 100644 --- a/CCDB/include/CCDB/CcdbApi.h +++ b/CCDB/include/CCDB/CcdbApi.h @@ -281,7 +281,7 @@ class CcdbApi //: public DatabaseInterface * @return: True in case operation successful or false if there was a failure/problem. */ bool retrieveBlob(std::string const& path, std::string const& targetdir, std::map const& metadata, long timestamp, - bool preservePathStructure = true, std::string const& localFileName = "snapshot.root", std::string const& createdNotAfter = "", std::string const& createdNotBefore = "") const; + bool preservePathStructure = true, std::string const& localFileName = "snapshot.root", std::string const& createdNotAfter = "", std::string const& createdNotBefore = "", std::map* headers = nullptr) const; /** * Retrieve the headers of a CCDB entry, if it exists. @@ -556,7 +556,7 @@ class CcdbApi //: public DatabaseInterface * @param tcl The TClass object describing the serialized type * @return raw pointer to created object */ - void* downloadFilesystemContent(std::string const& fullUrl, std::type_info const& tinfo, std::map* headers) const; + void* downloadFilesystemContent(std::string const& fullUrl, std::type_info const& tinfo, std::map* headers) const; // initialize the TGrid (Alien connection) bool initTGrid() const; @@ -576,9 +576,6 @@ class CcdbApi //: public DatabaseInterface // convert type_info to TClass, throw on failure static TClass* tinfo2TClass(std::type_info const& tinfo); - // split string on delimiters and return tokens as vector - std::vector splitString(const std::string& str, const char* delimiters); - typedef size_t (*CurlWriteCallback)(void*, size_t, size_t, void*); void initCurlOptionsForRetrieve(CURL* curlHandle, void* pointer, CurlWriteCallback writeCallback, bool followRedirect = true) const; diff --git a/CCDB/src/BasicCCDBManager.cxx b/CCDB/src/BasicCCDBManager.cxx index bcf88554578c1..53055d0d1231d 100644 --- a/CCDB/src/BasicCCDBManager.cxx +++ b/CCDB/src/BasicCCDBManager.cxx @@ -13,6 +13,8 @@ // Created by Sandro Wenzel on 2019-08-14. // #include "CCDB/BasicCCDBManager.h" +#include "Framework/ServiceRegistryRef.h" +#include "Framework/DataProcessingStats.h" #include #include #include @@ -99,7 +101,7 @@ std::pair CCDBManagerInstance::getRunDuration(int runnumber, b std::string CCDBManagerInstance::getSummaryString() const { - std::string res = fmt::format("{} queries, {} bytes", mQueries, fmt::group_digits(mFetchedSize)); + std::string res = fmt::format("{} queries, {} fetched / {} requested bytes", mQueries, fmt::group_digits(mFetchedSize), fmt::group_digits(mRequestedSize)); if (mCachingEnabled) { res += fmt::format(" for {} objects", mCache.size()); } diff --git a/CCDB/src/CcdbApi.cxx b/CCDB/src/CcdbApi.cxx index c9d2fad882aa1..93a79ad56c477 100644 --- a/CCDB/src/CcdbApi.cxx +++ b/CCDB/src/CcdbApi.cxx @@ -24,6 +24,7 @@ #include "Framework/DataTakingContext.h" #include #include +#include #include #include #include @@ -39,13 +40,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include "rapidjson/document.h" #include "rapidjson/writer.h" @@ -116,13 +117,7 @@ CcdbApi::~CcdbApi() void CcdbApi::setUniqueAgentID() { - std::string host = boost::asio::ip::host_name(); - char const* jobID = getenv("ALIEN_PROC_ID"); - if (jobID) { - mUniqueAgentID = fmt::format("{}-{}-{}-{}", host, getCurrentTimestamp() / 1000, o2::utils::Str::getRandomString(6), jobID); - } else { - mUniqueAgentID = fmt::format("{}-{}-{}", host, getCurrentTimestamp() / 1000, o2::utils::Str::getRandomString(6)); - } + mUniqueAgentID = TAlienUserAgent::BasedOnEnvironment().ToString(); } bool CcdbApi::checkAlienToken() @@ -164,6 +159,10 @@ void CcdbApi::curlInit() void CcdbApi::init(std::string const& host) { + if (host.empty()) { + throw std::invalid_argument("Empty url passed CcdbApi, cannot initialize. Aborting."); + } + // if host is prefixed with "file://" this is a local snapshot // in this case we init the API in snapshot (readonly) mode constexpr const char* SNAPSHOTPREFIX = "file://"; @@ -214,8 +213,7 @@ void CcdbApi::init(std::string const& host) snapshotReport += ')'; } - mNeedAlienToken = (host.find("https://") != std::string::npos) || (host.find("alice-ccdb.cern.ch") != std::string::npos); - + mNeedAlienToken = (host.find("https://") != std::string::npos) || (host.find("alice-ccdb.cern.ch") != std::string::npos) || (host.find("ccdb-test.cern.ch") != std::string::npos); // Set the curl timeout. It can be forced with an env var or it has different defaults based on the deployment mode. if (getenv("ALICEO2_CCDB_CURL_TIMEOUT_DOWNLOAD")) { auto timeout = atoi(getenv("ALICEO2_CCDB_CURL_TIMEOUT_DOWNLOAD")); @@ -232,7 +230,7 @@ void CcdbApi::init(std::string const& host) deploymentMode == o2::framework::DeploymentMode::FST) { mCurlTimeoutDownload = 15; } else if (deploymentMode == o2::framework::DeploymentMode::Local) { - mCurlTimeoutDownload = 1; + mCurlTimeoutDownload = 5; } } @@ -297,7 +295,7 @@ void CcdbApi::updateMetaInformationInLocalFile(std::string const& filename, std: */ std::string sanitizeObjectName(const std::string& objectName) { - string tmpObjectName = objectName; + std::string tmpObjectName = objectName; tmpObjectName.erase(std::remove_if(tmpObjectName.begin(), tmpObjectName.end(), [](auto const& c) -> bool { return (!std::isalnum(c) && c != '_' && c != '/' && c != '.'); }), tmpObjectName.end()); @@ -370,6 +368,10 @@ int CcdbApi::storeAsBinaryFile(const char* buffer, size_t size, const std::strin sanitizedEndValidityTimestamp = getFutureTimestamp(60 * 60 * 24 * 1); } if (mInSnapshotMode) { // write local file + if (filename.empty() || buffer == nullptr || size == 0) { + LOGP(alarm, "Snapshot mode does not support headers-only upload"); + return -3; + } auto pthLoc = getSnapshotDir(mSnapshotTopPath, path); o2::utils::createDirectoriesIfAbsent(pthLoc); auto flLoc = getSnapshotFile(mSnapshotTopPath, path, filename); @@ -413,8 +415,14 @@ int CcdbApi::storeAsBinaryFile(const char* buffer, size_t size, const std::strin auto mime = curl_mime_init(curl); auto field = curl_mime_addpart(mime); curl_mime_name(field, "send"); - curl_mime_filedata(field, filename.c_str()); - curl_mime_data(field, buffer, size); + if (!filename.empty()) { + curl_mime_filedata(field, filename.c_str()); + } + if (buffer != nullptr && size > 0) { + curl_mime_data(field, buffer, size); + } else { + curl_mime_data(field, "", 0); + } struct curl_slist* headerlist = nullptr; static const char buf[] = "Expect:"; @@ -431,7 +439,7 @@ int CcdbApi::storeAsBinaryFile(const char* buffer, size_t size, const std::strin CURLcode res = CURL_LAST; for (size_t hostIndex = 0; hostIndex < hostsPool.size() && res > 0; hostIndex++) { - string fullUrl = getFullUrlForStorage(curl, path, objectType, metadata, sanitizedStartValidityTimestamp, sanitizedEndValidityTimestamp, hostIndex); + std::string fullUrl = getFullUrlForStorage(curl, path, objectType, metadata, sanitizedStartValidityTimestamp, sanitizedEndValidityTimestamp, hostIndex); LOG(debug3) << "Full URL Encoded: " << fullUrl; /* what URL that receives this POST */ curl_easy_setopt(curl, CURLOPT_URL, fullUrl.c_str()); @@ -476,30 +484,30 @@ int CcdbApi::storeAsTFile(const TObject* rootObject, std::string const& path, st return storeAsBinaryFile(img->data(), img->size(), info.getFileName(), info.getObjectType(), path, metadata, startValidityTimestamp, endValidityTimestamp, maxSize); } -string CcdbApi::getFullUrlForStorage(CURL* curl, const string& path, const string& objtype, - const map& metadata, - long startValidityTimestamp, long endValidityTimestamp, int hostIndex) const +std::string CcdbApi::getFullUrlForStorage(CURL* curl, const std::string& path, const std::string& objtype, + const std::map& metadata, + long startValidityTimestamp, long endValidityTimestamp, int hostIndex) const { // Prepare timestamps - string startValidityString = getTimestampString(startValidityTimestamp < 0 ? getCurrentTimestamp() : startValidityTimestamp); - string endValidityString = getTimestampString(endValidityTimestamp < 0 ? getFutureTimestamp(60 * 60 * 24 * 1) : endValidityTimestamp); + std::string startValidityString = getTimestampString(startValidityTimestamp < 0 ? getCurrentTimestamp() : startValidityTimestamp); + std::string endValidityString = getTimestampString(endValidityTimestamp < 0 ? getFutureTimestamp(60 * 60 * 24 * 1) : endValidityTimestamp); // Get url - string url = getHostUrl(hostIndex); + std::string url = getHostUrl(hostIndex); // Build URL - string fullUrl = url + "/" + path + "/" + startValidityString + "/" + endValidityString + "/"; + std::string fullUrl = url + "/" + path + "/" + startValidityString + "/" + endValidityString + "/"; // Add type as part of metadata // we need to URL encode the object type, since in case it has special characters (like the "<", ">" for templated classes) it won't work otherwise char* objtypeEncoded = curl_easy_escape(curl, objtype.c_str(), objtype.size()); - fullUrl += "ObjectType=" + string(objtypeEncoded) + "/"; + fullUrl += "ObjectType=" + std::string(objtypeEncoded) + "/"; curl_free(objtypeEncoded); // Add general metadata for (auto& kv : metadata) { - string mfirst = kv.first; - string msecond = kv.second; + std::string mfirst = kv.first; + std::string msecond = kv.second; // same trick for the metadata as for the object type char* mfirstEncoded = curl_easy_escape(curl, mfirst.c_str(), mfirst.size()); char* msecondEncoded = curl_easy_escape(curl, msecond.c_str(), msecond.size()); - fullUrl += string(mfirstEncoded) + "=" + string(msecondEncoded) + "/"; + fullUrl += std::string(mfirstEncoded) + "=" + std::string(msecondEncoded) + "/"; curl_free(mfirstEncoded); curl_free(msecondEncoded); } @@ -507,26 +515,26 @@ string CcdbApi::getFullUrlForStorage(CURL* curl, const string& path, const strin } // todo make a single method of the one above and below -string CcdbApi::getFullUrlForRetrieval(CURL* curl, const string& path, const map& metadata, long timestamp, int hostIndex) const +std::string CcdbApi::getFullUrlForRetrieval(CURL* curl, const std::string& path, const std::map& metadata, long timestamp, int hostIndex) const { if (mInSnapshotMode) { return getSnapshotFile(mSnapshotTopPath, path); } // Prepare timestamps - string validityString = getTimestampString(timestamp < 0 ? getCurrentTimestamp() : timestamp); + std::string validityString = getTimestampString(timestamp < 0 ? getCurrentTimestamp() : timestamp); // Get host url - string hostUrl = getHostUrl(hostIndex); + std::string hostUrl = getHostUrl(hostIndex); // Build URL - string fullUrl = hostUrl + "/" + path + "/" + validityString + "/"; + std::string fullUrl = hostUrl + "/" + path + "/" + validityString + "/"; // Add metadata for (auto& kv : metadata) { - string mfirst = kv.first; - string msecond = kv.second; + std::string mfirst = kv.first; + std::string msecond = kv.second; // trick for the metadata in case it contains special characters char* mfirstEncoded = curl_easy_escape(curl, mfirst.c_str(), mfirst.size()); char* msecondEncoded = curl_easy_escape(curl, msecond.c_str(), msecond.size()); - fullUrl += string(mfirstEncoded) + "=" + string(msecondEncoded) + "/"; + fullUrl += std::string(mfirstEncoded) + "=" + std::string(msecondEncoded) + "/"; curl_free(mfirstEncoded); curl_free(msecondEncoded); } @@ -755,7 +763,7 @@ bool CcdbApi::receiveObject(void* dataHolder, std::string const& path, std::map< CURLcode curlResultCode = CURL_LAST; for (size_t hostIndex = 0; hostIndex < hostsPool.size() && (responseCode >= 400 || curlResultCode > 0); hostIndex++) { - string fullUrl = getFullUrlForRetrieval(curlHandle, path, metadata, timestamp, hostIndex); + std::string fullUrl = getFullUrlForRetrieval(curlHandle, path, metadata, timestamp, hostIndex); curl_easy_setopt(curlHandle, CURLOPT_URL, fullUrl.c_str()); curlResultCode = CURL_perform(curlHandle); @@ -830,7 +838,7 @@ TObject* CcdbApi::retrieveFromTFile(std::string const& path, std::map const& metadata, - long timestamp, bool preservePath, std::string const& localFileName, std::string const& createdNotAfter, std::string const& createdNotBefore) const + long timestamp, bool preservePath, std::string const& localFileName, std::string const& createdNotAfter, std::string const& createdNotBefore, std::map* outHeaders) const { // we setup the target path for this blob @@ -878,6 +886,9 @@ bool CcdbApi::retrieveBlob(std::string const& path, std::string const& targetdir CCDBQuery querysummary(path, metadata, timestamp); updateMetaInformationInLocalFile(targetpath.c_str(), &headers, &querysummary); + if (outHeaders) { + *outHeaders = std::move(headers); + } return true; } @@ -885,7 +896,7 @@ void CcdbApi::snapshot(std::string const& ccdbrootpath, std::string const& local { // query all subpaths to ccdbrootpath const auto allfolders = getAllFolders(ccdbrootpath); - std::map metadata; + std::map metadata; for (auto& folder : allfolders) { retrieveBlob(folder, localDir, metadata, timestamp); } @@ -958,14 +969,14 @@ void* CcdbApi::extractFromLocalFile(std::string const& filename, std::type_info bool CcdbApi::initTGrid() const { - if (mNeedAlienToken && !mAlienInstance) { + if (mNeedAlienToken && !gGrid) { static bool allowNoToken = getenv("ALICEO2_CCDB_NOTOKENCHECK") && atoi(getenv("ALICEO2_CCDB_NOTOKENCHECK")); if (!allowNoToken && !checkAlienToken()) { LOG(fatal) << "Alien Token Check failed - Please get an alien token before running with https CCDB endpoint, or alice-ccdb.cern.ch!"; } - mAlienInstance = TGrid::Connect("alien"); + TGrid::Connect("alien"); static bool errorShown = false; - if (!mAlienInstance && errorShown == false) { + if (!gGrid && errorShown == false) { if (allowNoToken) { LOG(error) << "TGrid::Connect returned nullptr. May be due to missing alien token"; } else { @@ -974,10 +985,10 @@ bool CcdbApi::initTGrid() const errorShown = true; } } - return mAlienInstance != nullptr; + return gGrid != nullptr; } -void* CcdbApi::downloadFilesystemContent(std::string const& url, std::type_info const& tinfo, std::map* headers) const +void* CcdbApi::downloadFilesystemContent(std::string const& url, std::type_info const& tinfo, std::map* headers) const { if ((url.find("alien:/", 0) != std::string::npos) && !initTGrid()) { return nullptr; @@ -1016,7 +1027,7 @@ 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, std::type_info const& tinfo, std::map* headers) const +void* CcdbApi::navigateURLsAndRetrieveContent(CURL* curl_handle, std::string const& url, std::type_info const& tinfo, std::map* headers) const { // a global internal data structure that can be filled with HTTP header information // static --> to avoid frequent alloc/dealloc as optimization @@ -1164,7 +1175,7 @@ void* CcdbApi::retrieveFromTFile(std::type_info const& tinfo, std::string const& CURL* curl_handle = curl_easy_init(); curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, mUniqueAgentID.c_str()); - string fullUrl = getFullUrlForRetrieval(curl_handle, path, metadata, timestamp); // todo check if function still works correctly in case mInSnapshotMode + std::string fullUrl = getFullUrlForRetrieval(curl_handle, path, metadata, timestamp); // todo check if function still works correctly in case mInSnapshotMode // if we are in snapshot mode we can simply open the file; extract the object and return if (mInSnapshotMode) { auto res = extractFromLocalFile(fullUrl, tinfo, headers); @@ -1218,8 +1229,8 @@ std::string CcdbApi::list(std::string const& path, bool latestOnly, std::string curl_easy_setopt(curl, CURLOPT_USERAGENT, mUniqueAgentID.c_str()); struct curl_slist* headers = nullptr; - headers = curl_slist_append(headers, (string("Accept: ") + returnFormat).c_str()); - headers = curl_slist_append(headers, (string("Content-Type: ") + returnFormat).c_str()); + headers = curl_slist_append(headers, (std::string("Accept: ") + returnFormat).c_str()); + headers = curl_slist_append(headers, (std::string("Content-Type: ") + returnFormat).c_str()); if (createdNotAfter >= 0) { headers = curl_slist_append(headers, ("If-Not-After: " + std::to_string(createdNotAfter)).c_str()); } @@ -1230,7 +1241,7 @@ std::string CcdbApi::list(std::string const& path, bool latestOnly, std::string curlSetSSLOptions(curl); - string fullUrl; + std::string fullUrl; // Perform the request, res will get the return code for (size_t hostIndex = 0; hostIndex < hostsPool.size() && res != CURLE_OK; hostIndex++) { fullUrl = getHostUrl(hostIndex); @@ -1290,7 +1301,7 @@ void CcdbApi::truncate(std::string const& path) const CURLcode res; stringstream fullUrl; for (size_t i = 0; i < hostsPool.size(); i++) { - string url = getHostUrl(i); + std::string url = getHostUrl(i); fullUrl << url << "/truncate/" << path; curl = curl_easy_init(); @@ -1436,7 +1447,7 @@ std::map CcdbApi::retrieveHeaders(std::string const& p auto do_remote_header_call = [this, &path, &metadata, timestamp]() -> std::map { CURL* curl = curl_easy_init(); CURLcode res = CURL_LAST; - string fullUrl = getFullUrlForRetrieval(curl, path, metadata, timestamp); + std::string fullUrl = getFullUrlForRetrieval(curl, path, metadata, timestamp); std::map headers; if (curl != nullptr) { @@ -1632,12 +1643,12 @@ int CcdbApi::updateMetadata(std::string const& path, std::map CcdbApi::splitString(const std::string& str, const char* delimiters) -{ - std::vector tokens; - char stringForStrTok[str.length() + 1]; - strcpy(stringForStrTok, str.c_str()); - char* token = strtok(stringForStrTok, delimiters); - while (token != nullptr) { - tokens.emplace_back(token); - token = strtok(nullptr, delimiters); - } - return tokens; -} - void CcdbApi::initHostsPool(std::string hosts) { - hostsPool = splitString(hosts, ",;"); + hostsPool.clear(); + auto splitted = hosts | std::views::transform([](char c) { return (c == ';') ? ',' : c; }) | std::views::split(','); + for (auto&& part : splitted) { + hostsPool.emplace_back(part.begin(), part.end()); + } } std::string CcdbApi::getHostUrl(int hostIndex) const @@ -1728,7 +1730,7 @@ void CcdbApi::scheduleDownload(RequestContext& requestContext, size_t* requestCo CURL* curl_handle = curl_easy_init(); curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, mUniqueAgentID.c_str()); - string fullUrl = getFullUrlForRetrieval(curl_handle, requestContext.path, requestContext.metadata, requestContext.timestamp); + std::string fullUrl = getFullUrlForRetrieval(curl_handle, requestContext.path, requestContext.metadata, requestContext.timestamp); curl_slist* options_list = nullptr; initCurlHTTPHeaderOptionsForRetrieve(curl_handle, options_list, requestContext.timestamp, &requestContext.headers, requestContext.etag, requestContext.createdNotAfter, requestContext.createdNotBefore); diff --git a/CCDB/src/UploadTool.cxx b/CCDB/src/UploadTool.cxx index 44b8d8e20bc7d..9aba417b4f4a9 100644 --- a/CCDB/src/UploadTool.cxx +++ b/CCDB/src/UploadTool.cxx @@ -147,33 +147,44 @@ int main(int argc, char* argv[]) meta[p.first] = p.second; } - TFile f(filename.c_str()); - auto key = f.GetKey(keyname.c_str()); - if (key) { - // get type of key - auto classname = key->GetClassName(); - auto tcl = TClass::GetClass(classname); - auto object = f.Get(keyname.c_str()); - if (tcl->InheritsFrom("TTree")) { - auto tree = static_cast(object); - tree->LoadBaskets(0x1L << 32); // make tree memory based - tree->SetDirectory(nullptr); - } - // convert classname to typeinfo - // typeinfo - auto ti = tcl->GetTypeInfo(); - - std::cout << " Uploading an object of type " << key->GetClassName() - << " to path " << path << " with timestamp validity from " << starttimestamp - << " to " << endtimestamp << "\n"; - - api.storeAsTFile_impl(object, *ti, path, meta, starttimestamp, endtimestamp); + if (filename == "headersOnly") { + auto ent = meta.find("Redirect"); + std::cout << " Uploading a headers-only object to path " << path << " with timestamp validity from " << starttimestamp << " to " << endtimestamp + << " Redirection to: " << ((ent != meta.end()) ? ent->second : std::string{"none"}) << "\n"; + api.storeAsBinaryFile(nullptr, 0, "ignored", "", path, meta, starttimestamp, endtimestamp); if (!api.isSnapshotMode() && meta.find("adjustableEOV") != meta.end() && meta.find("default") == meta.end()) { - o2::ccdb::CcdbObjectInfo oi(path, classname, filename, meta, starttimestamp, endtimestamp); + o2::ccdb::CcdbObjectInfo oi(path, "", "", meta, starttimestamp, endtimestamp); o2::ccdb::adjustOverriddenEOV(api, oi); } } else { - std::cerr << "Key " << keyname << " does not exist\n"; + TFile f(filename.c_str()); + auto key = f.GetKey(keyname.c_str()); + if (key) { + // get type of key + auto classname = key->GetClassName(); + auto tcl = TClass::GetClass(classname); + auto object = f.Get(keyname.c_str()); + if (tcl->InheritsFrom("TTree")) { + auto tree = static_cast(object); + tree->LoadBaskets(0x1L << 32); // make tree memory based + tree->SetDirectory(nullptr); + } + // convert classname to typeinfo + // typeinfo + auto ti = tcl->GetTypeInfo(); + + std::cout << " Uploading an object of type " << key->GetClassName() + << " to path " << path << " with timestamp validity from " << starttimestamp + << " to " << endtimestamp << "\n"; + + api.storeAsTFile_impl(object, *ti, path, meta, starttimestamp, endtimestamp); + if (!api.isSnapshotMode() && meta.find("adjustableEOV") != meta.end() && meta.find("default") == meta.end()) { + o2::ccdb::CcdbObjectInfo oi(path, classname, filename, meta, starttimestamp, endtimestamp); + o2::ccdb::adjustOverriddenEOV(api, oi); + } + } else { + std::cerr << "Key " << keyname << " does not exist\n"; + } } return 0; diff --git a/CCDB/test/testBasicCCDBManager.cxx b/CCDB/test/testBasicCCDBManager.cxx index 7cd143f655547..6359bf2f5ccf4 100644 --- a/CCDB/test/testBasicCCDBManager.cxx +++ b/CCDB/test/testBasicCCDBManager.cxx @@ -26,7 +26,7 @@ using namespace o2::ccdb; -static string basePath; +static std::string basePath; std::string ccdbUrl = "http://ccdb-test.cern.ch:8080"; bool hostReachable = false; @@ -43,7 +43,7 @@ struct Fixture { std::cout << "Is host reachable ? --> " << hostReachable << std::endl; char hostname[_POSIX_HOST_NAME_MAX]; gethostname(hostname, _POSIX_HOST_NAME_MAX); - basePath = string("Test/") + hostname + "/pid" + getpid() + "/BasicCCDBManager/"; + basePath = std::string("Test/") + hostname + "/pid" + getpid() + "/BasicCCDBManager/"; std::cout << "Path we will use in this test suite : " + basePath << std::endl; } ~Fixture() diff --git a/CCDB/test/testCcdbApi.cxx b/CCDB/test/testCcdbApi.cxx index c834f2f30f64a..1b6a5d6f0967a 100644 --- a/CCDB/test/testCcdbApi.cxx +++ b/CCDB/test/testCcdbApi.cxx @@ -45,8 +45,8 @@ using namespace o2::ccdb; namespace utf = boost::unit_test; namespace tt = boost::test_tools; -static string ccdbUrl; -static string basePath; +static std::string ccdbUrl; +static std::string basePath; bool hostReachable = false; /** @@ -63,7 +63,7 @@ struct Fixture { cout << "Is host reachable ? --> " << hostReachable << endl; char hostname[_POSIX_HOST_NAME_MAX]; gethostname(hostname, _POSIX_HOST_NAME_MAX); - basePath = string("Test/TestCcdbApi/") + hostname + "/pid" + getpid() + "/"; + basePath = std::string("Test/TestCcdbApi/") + hostname + "/pid" + getpid() + "/"; // Replace dashes by underscores to avoid problems in the creation of local directories std::replace(basePath.begin(), basePath.end(), '-','_'); cout << "Path we will use in this test suite : " + basePath << endl; @@ -72,7 +72,7 @@ struct Fixture { { if (hostReachable) { CcdbApi api; - map metadata; + std::map metadata; api.init(ccdbUrl); api.truncate(basePath + "*"); cout << "Test data truncated (" << basePath << ")" << endl; @@ -104,7 +104,7 @@ struct test_fixture { ~test_fixture() = default; CcdbApi api; - map metadata; + std::map metadata; }; BOOST_AUTO_TEST_CASE(storeTMemFile_test, *utf::precondition(if_reachable())) @@ -153,7 +153,7 @@ BOOST_AUTO_TEST_CASE(store_retrieve_TMemFile_templated_test, *utf::precondition( BOOST_CHECK(f.api.retrieveFromTFileAny(basePath + "CCDBPath", f.metadata) == nullptr); // try to get the headers back and to find the metadata - map md; + std::map md; path2 = f.api.retrieveFromTFileAny(basePath + "CCDBPath", f.metadata, -1, &md); BOOST_CHECK_EQUAL(md.count("Hello"), 1); BOOST_CHECK_EQUAL(md["Hello"], "World"); @@ -345,7 +345,7 @@ BOOST_AUTO_TEST_CASE(delete_test, *utf::precondition(if_reachable())) BOOST_CHECK(h2 == nullptr); } -void countItems(const string& s, int& countObjects, int& countSubfolders) +void countItems(const std::string& s, int& countObjects, int& countSubfolders) { countObjects = 0; countSubfolders = 0; @@ -368,7 +368,7 @@ BOOST_AUTO_TEST_CASE(list_test, *utf::precondition(if_reachable())) test_fixture f; // test non-empty top dir - string s = f.api.list("", "application/json"); // top dir + std::string s = f.api.list("", "application/json"); // top dir long nbLines = std::count(s.begin(), s.end(), '\n') + 1; BOOST_CHECK(nbLines > 5); @@ -436,7 +436,7 @@ BOOST_AUTO_TEST_CASE(TestHeaderParsing) BOOST_AUTO_TEST_CASE(TestFetchingHeaders, *utf::precondition(if_reachable())) { // first store the object - string objectPath = basePath + "objectETag"; + std::string objectPath = basePath + "objectETag"; test_fixture f; TH1F h1("objectETag", "objectETag", 100, 0, 99); f.api.storeAsTFile(&h1, objectPath, f.metadata); @@ -445,7 +445,7 @@ BOOST_AUTO_TEST_CASE(TestFetchingHeaders, *utf::precondition(if_reachable())) std::string etag; std::vector headers; std::vector pfns; - string path = objectPath + "/" + std::to_string(getCurrentTimestamp()); + std::string path = objectPath + "/" + std::to_string(getCurrentTimestamp()); auto updated = CcdbApi::getCCDBEntryHeaders("http://ccdb-test.cern.ch:8080/" + path, etag, headers); BOOST_CHECK_EQUAL(updated, true); BOOST_REQUIRE(headers.size() != 0); @@ -462,7 +462,7 @@ BOOST_AUTO_TEST_CASE(TestRetrieveHeaders, *utf::precondition(if_reachable())) TH1F h1("object1", "object1", 100, 0, 99); cout << "storing object 1 in " << basePath << "Test" << endl; - map metadata; + std::map metadata; metadata["custom"] = "whatever"; f.api.storeAsTFile(&h1, basePath + "Test", metadata); @@ -498,7 +498,7 @@ BOOST_AUTO_TEST_CASE(TestUpdateMetadata, *utf::precondition(if_reachable())) // upload an object TH1F h1("object1", "object1", 100, 0, 99); cout << "storing object 1 in " << basePath << "Test" << endl; - map metadata; + std::map metadata; metadata["custom"] = "whatever"; metadata["id"] = "first"; f.api.storeAsTFile(&h1, basePath + "Test", metadata); @@ -507,10 +507,10 @@ BOOST_AUTO_TEST_CASE(TestUpdateMetadata, *utf::precondition(if_reachable())) std::map headers = f.api.retrieveHeaders(basePath + "Test", metadata); BOOST_CHECK(headers.count("custom") > 0); BOOST_CHECK(headers.at("custom") == "whatever"); - string firstID = headers.at("ETag"); + std::string firstID = headers.at("ETag"); firstID.erase(std::remove(firstID.begin(), firstID.end(), '"'), firstID.end()); - map newMetadata; + std::map newMetadata; newMetadata["custom"] = "somethingelse"; // update the metadata and check @@ -529,7 +529,7 @@ BOOST_AUTO_TEST_CASE(TestUpdateMetadata, *utf::precondition(if_reachable())) // get id cout << "get id" << endl; headers = f.api.retrieveHeaders(basePath + "Test", metadata); - string secondID = headers.at("ETag"); + std::string secondID = headers.at("ETag"); secondID.erase(std::remove(secondID.begin(), secondID.end(), '"'), secondID.end()); // update the metadata by id @@ -589,4 +589,11 @@ BOOST_AUTO_TEST_CASE(vectored) for (auto context : contexts) { BOOST_CHECK(context.dest.size() != 0); } -} \ No newline at end of file +} + +BOOST_AUTO_TEST_CASE(empty_url) +{ + CcdbApi api; + string url = ""; + BOOST_CHECK_EXCEPTION(api.init(url), invalid_argument, [](std::invalid_argument const&) -> bool { return true; }); +} diff --git a/CCDB/test/testCcdbApiHeaders.cxx b/CCDB/test/testCcdbApiHeaders.cxx new file mode 100644 index 0000000000000..bcfa2a5b44bc2 --- /dev/null +++ b/CCDB/test/testCcdbApiHeaders.cxx @@ -0,0 +1,413 @@ +// Copyright 2019-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file testCcdbApiHeaders.cxx +/// \brief Test BasicCCDBManager header/metadata information functionality with caching +/// \author martin.oines.eide@cern.ch + +#define BOOST_TEST_MODULE CCDB +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "CCDB/CcdbApi.h" +#include + +static std::string basePath; +// std::string ccdbUrl = "http://localhost:8080"; +std::string ccdbUrl = "http://ccdb-test.cern.ch:8080"; +bool hostReachable = false; + +/** + * Global fixture, ie general setup and teardown + * Copied from testBasicCCDBManager.cxx + */ +struct Fixture { + Fixture() + { + auto& ccdbManager = o2::ccdb::BasicCCDBManager::instance(); + if (std::getenv("ALICEO2_CCDB_HOST")) { + ccdbUrl = std::string(std::getenv("ALICEO2_CCDB_HOST")); + } + ccdbManager.setURL(ccdbUrl); + hostReachable = ccdbManager.getCCDBAccessor().isHostReachable(); + char hostname[_POSIX_HOST_NAME_MAX]; + gethostname(hostname, _POSIX_HOST_NAME_MAX); + basePath = std::string("Users/m/meide/Tests/") + hostname + "/pid-" + getpid() + "/BasicCCDBManager/"; + + LOG(info) << "Path we will use in this test suite : " + basePath << std::endl; + LOG(info) << "ccdb url: " << ccdbUrl << std::endl; + LOG(info) << "Is host reachable ? --> " << hostReachable << std::endl; + } + ~Fixture() + { + if (hostReachable) { + o2::ccdb::BasicCCDBManager::instance().getCCDBAccessor().truncate(basePath + "*"); // This deletes the data after test is run, disable if you want to inspect the data + LOG(info) << "Test data truncated/deleted (" << basePath << ")" << std::endl; + } + } +}; +BOOST_GLOBAL_FIXTURE(Fixture); +/** + * Just an accessor to the hostReachable variable to be used to determine whether tests can be ran or not. + * Copied from testCcdbApi.cxx + */ +struct if_reachable { + boost::test_tools::assertion_result operator()(boost::unit_test::test_unit_id) + { + return hostReachable; + } +}; + +// Only compare known and stable keys (avoid volatile ones like Date) +static const std::set sStableKeys = { + "ETag", + "Valid-From", + "Valid-Until", + "Created", + "Last-Modified", + "Content-Disposition", + "Content-Location", + "path", + "partName", + "Content-MD5", + "Hello" // TODO find other headers to compare to +}; + +// Test that we get back the same header header keys as we put in (for stable keys) + +BOOST_AUTO_TEST_CASE(testCachedHeaders, *boost::unit_test::precondition(if_reachable())) +{ + /// ━━━━━━━ ARRANGE ━━━━━━━━━ + // First store objects to test with + auto& ccdbManager = o2::ccdb::BasicCCDBManager::instance(); + std::string pathA = basePath + "CachingA"; + std::string pathB = basePath + "CachingB"; + std::string pathC = basePath + "CachingC"; + std::string ccdbObjO = "testObjectO"; + std::string ccdbObjN = "testObjectN"; + std::string ccdbObjX = "testObjectX"; + std::map md = { + {"Hello", "World"}, + {"Key1", "Value1"}, + {"Key2", "Value2"}, + }; + long start = 1000, stop = 3000; + ccdbManager.getCCDBAccessor().storeAsTFileAny(&ccdbObjO, pathA, md, start, stop); + ccdbManager.getCCDBAccessor().storeAsTFileAny(&ccdbObjN, pathB, md, start, stop); + ccdbManager.getCCDBAccessor().storeAsTFileAny(&ccdbObjX, pathC, md, start, stop); + // initilize the BasicCCDBManager + ccdbManager.clearCache(); + ccdbManager.setCaching(true); // This is what we want to test. + + /// ━━━━━━━━━━━ ACT ━━━━━━━━━━━━ + // Plan: get one object, then another, then the first again and check the headers are the same + std::map headers1, headers2, headers3; + + auto* obj1 = ccdbManager.getForTimeStamp(pathA, (start + stop) / 2, &headers1); + auto* obj2 = ccdbManager.getForTimeStamp(pathB, (start + stop) / 2, &headers2); + auto* obj3 = ccdbManager.getForTimeStamp(pathA, (start + stop) / 2, &headers3); // Should lead to a cache hit! + + /// ━━━━━━━━━━━ ASSERT ━━━━━━━━━━━━ + /// Check that we got something + BOOST_REQUIRE(obj1 != nullptr); + BOOST_REQUIRE(obj2 != nullptr); + BOOST_REQUIRE(obj3 != nullptr); + + LOG(debug) << "obj1: " << *obj1; + LOG(debug) << "obj2: " << *obj2; + LOG(debug) << "obj3: " << *obj3; + + // Sanity check + /// Check that the objects are correct + BOOST_TEST(*obj1 == ccdbObjO); + BOOST_TEST(*obj3 == ccdbObjO); + BOOST_TEST(obj3 == obj1); // should be the same object in memory since it is cached + + BOOST_TEST(obj2 != obj1); + + (*obj1) = "ModifiedObject"; + BOOST_TEST(*obj1 == "ModifiedObject"); + BOOST_TEST(*obj3 == "ModifiedObject"); // obj3 and obj1 are the same object in memory + + // Check that the headers are the same for the two retrievals of the same object + BOOST_REQUIRE(headers1.size() != 0); + BOOST_REQUIRE(headers3.size() != 0); + + LOG(debug) << "Headers1 size: " << headers1.size(); + for (const auto& h : headers1) { + LOG(debug) << " " << h.first << " -> " << h.second; + } + LOG(debug) << "Headers3 size: " << headers3.size(); + for (const auto& h : headers3) { + LOG(debug) << " " << h.first << " -> " << h.second; + } + + for (const auto& stableKey : sStableKeys) { + LOG(info) << "Checking key: " << stableKey; + + BOOST_REQUIRE(headers1.count(stableKey) > 0); + BOOST_REQUIRE(headers3.count(stableKey) > 0); + BOOST_TEST(headers1.at(stableKey) == headers3.at(stableKey)); + } + BOOST_TEST(headers1 != headers2, "The headers for different objects should be different"); + + // Test that we can change the map and the two headers are not affected + headers1["NewKey"] = "NewValue"; + headers3["NewKey"] = "DifferentValue"; + BOOST_TEST(headers1["NewKey"] != headers3["NewKey"]); // This tests that we have a deep copy of the headers +} + +BOOST_AUTO_TEST_CASE(testNonCachedHeaders, *boost::unit_test::precondition(if_reachable())) +{ + /// ━━━━━━━ ARRANGE ━━━━━━━━━ + // First store objects to test with + auto& ccdbManager = o2::ccdb::BasicCCDBManager::instance(); + std::string pathA = basePath + "NonCachingA"; + std::string pathB = basePath + "NonCachingB"; + std::string ccdbObjO = "testObjectO"; + std::string ccdbObjN = "testObjectN"; + std::map md = { + {"Hello", "World"}, + {"Key1", "Value1"}, + {"Key2", "Value2"}, + }; + long start = 1000, stop = 2000; + ccdbManager.getCCDBAccessor().storeAsTFileAny(&ccdbObjO, pathA, md, start, stop); + ccdbManager.getCCDBAccessor().storeAsTFileAny(&ccdbObjN, pathB, md, start, stop); + // initilize the BasicCCDBManager + ccdbManager.clearCache(); + ccdbManager.setCaching(false); // This is what we want to test, no caching + + /// ━━━━━━━━━━━ ACT ━━━━━━━━━━━━ + // Plan: get one object, then another, then the first again. Then check that the contents is the same but not the object in memory + std::map headers1, headers2, headers3; + + auto* obj1 = ccdbManager.getForTimeStamp(pathA, (start + stop) / 2, &headers1); + auto* obj2 = ccdbManager.getForTimeStamp(pathB, (start + stop) / 2, &headers2); + auto* obj3 = ccdbManager.getForTimeStamp(pathA, (start + stop) / 2, &headers3); // Should not be cached since explicitly disabled + + ccdbManager.setCaching(true); // Restore default state + /// ━━━━━━━━━━━ ASSERT ━━━━━━━━━━━ + /// Check that we got something + BOOST_REQUIRE(obj1 != nullptr); + BOOST_REQUIRE(obj2 != nullptr); + BOOST_REQUIRE(obj3 != nullptr); + + LOG(debug) << "obj1: " << *obj1; + LOG(debug) << "obj2: " << *obj2; + LOG(debug) << "obj3: " << *obj3; + + // Sanity check + /// Check that the objects are correct + BOOST_TEST(*obj1 == ccdbObjO); + BOOST_TEST(*obj3 == ccdbObjO); + BOOST_TEST(obj2 != obj1); + BOOST_TEST(obj3 != obj1); // should NOT be the same object in memory + (*obj1) = "ModifiedObject"; + BOOST_TEST(*obj1 == "ModifiedObject"); + BOOST_TEST(*obj3 != "ModifiedObject"); // obj3 and obj1 are NOT the same object in memory + + BOOST_TEST(headers1.size() == headers3.size()); + + // Remove the date header since it may be different even for the same object since we might have asked in different seconds + headers1.erase("Date"); + headers3.erase("Date"); + BOOST_TEST(headers1 == headers3, "The headers for the same object should be the same even if not cached"); + + BOOST_TEST(headers1 != headers2, "The headers for different objects should be different"); + BOOST_TEST(headers1.size() != 0); + BOOST_TEST(headers3.size() != 0); + BOOST_TEST(headers2.size() != 0); + BOOST_TEST(headers1 != headers2, "The headers for different objects should be different"); + + // cleanup + delete obj1; + delete obj2; + delete obj3; +} + +BOOST_AUTO_TEST_CASE(CacheFirstRetrievalAndHeadersPersistence, *boost::unit_test::precondition(if_reachable())) +{ + /// ━━━━━━━ ARRANGE ━━━━━━━━━ + auto& mgr = o2::ccdb::BasicCCDBManager::instance(); + // Prepare two validity slots for same path to test ETag change later + std::string path = basePath + "ObjA"; + std::string objV1 = "ObjectVersion1"; + std::string objV2 = "ObjectVersion2"; + std::map meta1{ + {"UserKey1", "UValue1"}, + {"UserKey2", "UValue2"}}; + long v1start = 10'000; + long v1stop = 20'000; + long v2start = v1stop; // contiguous slot + long v2stop = v2start + (v1stop - v1start); + long mid1 = (v1start + v1stop) / 2; + // Store 2 versions + mgr.getCCDBAccessor().storeAsTFileAny(&objV1, path, meta1, v1start, v1stop); + mgr.getCCDBAccessor().storeAsTFileAny(&objV2, path, meta1, v2start, v2stop); + + mgr.clearCache(); + mgr.setCaching(true); + mgr.setFatalWhenNull(true); + mgr.setTimestamp(mid1); + + /// ━━━━━━━ACT━━━━━━━━━ + std::map headers1, headers2, headers4, headers5; + + // 1) First retrieval WITH headers inside 1st slot + auto* p1 = mgr.getForTimeStamp(path, mid1, &headers1); + size_t fetchedSizeAfterFirst = mgr.getFetchedSize(); + // 2) Second retrieval (cache hit) + auto* p2 = mgr.getForTimeStamp(path, mid1, &headers2); + size_t fetchedSizeAfterSecond = mgr.getFetchedSize(); + // 3) Third retrieval (cache hit) WITHOUT passing headers + auto* p3 = mgr.getForTimeStamp(path, mid1); + // 4) Fourth retrieval with headers again -> should still produce same headers + auto* p4 = mgr.getForTimeStamp(path, mid1, &headers4); + // 5) Fifth retrieval with headers again to check persistence + auto* p5 = mgr.getForTimeStamp(path, mid1, &headers5); + + mgr.setFatalWhenNull(false); // restore default + + /// ━━━━━━━ASSERT━━━━━━━━━ + + BOOST_TEST(p1 != nullptr); + BOOST_TEST(*p1 == objV1); + + BOOST_TEST(headers1.count("UserKey1") == 1); + BOOST_TEST(headers1.count("UserKey2") == 1); + BOOST_TEST(headers1["UserKey1"] == "UValue1"); + BOOST_TEST(headers1["UserKey2"] == "UValue2"); + BOOST_TEST(headers1.count("Valid-From") == 1); + BOOST_TEST(headers1.count("Valid-Until") == 1); + BOOST_TEST(headers1.count("ETag") == 1); + + /* Need to manually amend the headers1 to have cache valid until for comparison sake, + * the header is not set in the first request. + * It is only set if the internal cache of CCDB has seen this object before, apperently. + * This will never happen in this test since it was just created and not asked for before. + */ + headers1["Cache-Valid-Until"] = std::to_string(v1stop); + + /* In rare cases the header date might be different, if the second has ticked over between the requests + */ + headers1.erase("Date"); + headers2.erase("Date"); + headers4.erase("Date"); + headers5.erase("Date"); + + BOOST_TEST(p2 == p1); // same pointer for cached scenario + BOOST_TEST(headers2 == headers1); // identical header map + BOOST_TEST(fetchedSizeAfterSecond == fetchedSizeAfterFirst); // no new fetch + + BOOST_TEST(p3 == p1); + + BOOST_TEST(p4 == p1); + BOOST_TEST(headers4 == headers1); + + // Mutate the returned header map locally and ensure it does not corrupt internal cache + headers4["UserKey1"] = "Tampered"; + BOOST_TEST(p5 == p1); + BOOST_TEST(headers5["UserKey1"] == "UValue1"); // internal unchanged +} + +BOOST_AUTO_TEST_CASE(FailedFetchDoesNotGiveMetadata, *boost::unit_test::precondition(if_reachable())) +{ + + /// ━━━━━━━ ARRANGE ━━━━━━━━━ + auto& mgr = o2::ccdb::BasicCCDBManager::instance(); + std::string path = basePath + "FailThenRecover"; + std::string content = "ContentX"; + std::map meta{{"Alpha", "Beta"}}; + long s = 300'000, e = 310'000; + mgr.getCCDBAccessor().storeAsTFileAny(&content, path, meta, s, e); + mgr.clearCache(); + mgr.setCaching(true); + mgr.setFatalWhenNull(false); + + /// ━━━━━━━ ACT ━━━━━━━━━ + // Intentionally pick a timestamp outside validity to fail first + long badTS = s - 1000; + long goodTS = (s + e) / 2; + std::map hFail, hGood; + auto* badObj = mgr.getForTimeStamp(path, badTS, &hFail); + auto* goodObj = mgr.getForTimeStamp(path, goodTS, &hGood); + + /// ━━━━━━━ ASSERT ━━━━━━━━━ + BOOST_TEST(!hFail.empty()); // Should have some headers + BOOST_TEST(hFail["Alpha"] != "Beta"); // But not the metadata + BOOST_TEST(hGood.count("Alpha") == 1); + BOOST_TEST(hGood["Alpha"] == "Beta"); + + mgr.setFatalWhenNull(true); +} + +BOOST_AUTO_TEST_CASE(FirstCallWithoutHeadersThenWithHeaders, *boost::unit_test::precondition(if_reachable())) +{ + + auto& mgr = o2::ccdb::BasicCCDBManager::instance(); + std::string path = basePath + "LateHeaders"; + std::string body = "Late"; + std::map meta{{"LateKey", "LateVal"}}; + long s = 400'000, e = 410'000; + mgr.getCCDBAccessor().storeAsTFileAny(&body, path, meta, s, e); + + mgr.clearCache(); + mgr.setCaching(true); + long ts = (s + e) / 2; + + // 1) First call with nullptr headers + auto* first = mgr.getForTimeStamp(path, ts); + BOOST_TEST(first != nullptr); + BOOST_TEST(*first == body); + + // 2) Second call asking for headers - should return the full set + std::map h2; + auto* second = mgr.getForTimeStamp(path, ts, &h2); + BOOST_TEST(second == first); + BOOST_TEST(h2.count("LateKey") == 1); + BOOST_TEST(h2["LateKey"] == "LateVal"); + BOOST_TEST(h2.count("Valid-From") == 1); + BOOST_TEST(h2.count("Valid-Until") == 1); +} + +BOOST_AUTO_TEST_CASE(HeadersAreStableAcrossMultipleHits, *boost::unit_test::precondition(if_reachable())) +{ + + auto& mgr = o2::ccdb::BasicCCDBManager::instance(); + std::string path = basePath + "StableHeaders"; + std::string body = "Stable"; + std::map meta{{"HK", "HV"}}; + long s = 500'000, e = 510'000; + mgr.getCCDBAccessor().storeAsTFileAny(&body, path, meta, s, e); + + mgr.clearCache(); + mgr.setCaching(true); + long ts = (s + e) / 2; + + std::map h1; + auto* o1 = mgr.getForTimeStamp(path, ts, &h1); + BOOST_TEST(o1 != nullptr); + BOOST_TEST(h1.count("HK") == 1); + + std::string etag = h1["ETag"]; + for (int i = 0; i < 15; ++i) { + std::map hi; + auto* oi = mgr.getForTimeStamp(path, ts, &hi); + BOOST_TEST(oi == o1); + BOOST_TEST(hi.count("HK") == 1); + BOOST_TEST(hi["ETag"] == etag); + } +} diff --git a/CCDB/test/testCcdbApiMultipleUrls.cxx b/CCDB/test/testCcdbApiMultipleUrls.cxx index 331d0553c3aec..07ab0ddcb4dcf 100644 --- a/CCDB/test/testCcdbApiMultipleUrls.cxx +++ b/CCDB/test/testCcdbApiMultipleUrls.cxx @@ -24,8 +24,8 @@ using namespace o2::ccdb; namespace utf = boost::unit_test; namespace tt = boost::test_tools; -static string ccdbUrl; -static string basePath; +static std::string ccdbUrl; +static std::string basePath; bool hostReachable = false; /** @@ -40,14 +40,14 @@ struct Fixture { cout << "ccdb url: " << ccdbUrl << endl; hostReachable = api.isHostReachable(); cout << "Is host reachable ? --> " << hostReachable << endl; - basePath = string("Test/pid") + getpid() + "/"; + basePath = std::string("Test/pid") + getpid() + "/"; cout << "Path we will use in this test suite : " + basePath << endl; } ~Fixture() { if (hostReachable) { CcdbApi api; - map metadata; + std::map metadata; api.init(ccdbUrl); api.truncate(basePath + "*"); cout << "Test data truncated (" << basePath << ")" << endl; @@ -79,7 +79,7 @@ struct test_fixture { ~test_fixture() = default; CcdbApi api; - map metadata; + std::map metadata; }; BOOST_AUTO_TEST_CASE(storeAndRetrieve, *utf::precondition(if_reachable())) diff --git a/CCDB/test/testCcdbApi_ConfigParam.cxx b/CCDB/test/testCcdbApi_ConfigParam.cxx index 8b3521bfd468a..568669d05978f 100644 --- a/CCDB/test/testCcdbApi_ConfigParam.cxx +++ b/CCDB/test/testCcdbApi_ConfigParam.cxx @@ -47,8 +47,8 @@ using namespace o2::ccdb; namespace utf = boost::unit_test; namespace tt = boost::test_tools; -static string ccdbUrl; -static string basePath; +static std::string ccdbUrl; +static std::string basePath; bool hostReachable = false; /** @@ -64,14 +64,14 @@ struct Fixture { hostReachable = api.isHostReachable(); char hostname[_POSIX_HOST_NAME_MAX]; gethostname(hostname, _POSIX_HOST_NAME_MAX); - basePath = string("Test/") + hostname + "/pid" + getpid() + "/"; + basePath = std::string("Test/") + hostname + "/pid" + getpid() + "/"; cout << "Path we will use in this test suite : " + basePath << endl; } ~Fixture() { if (hostReachable) { CcdbApi api; - map metadata; + std::map metadata; api.init(ccdbUrl); api.truncate(basePath + "*"); cout << "Test data truncated (" << basePath << ")" << endl; @@ -103,7 +103,7 @@ struct test_fixture { ~test_fixture() = default; CcdbApi api; - map metadata; + std::map metadata; }; BOOST_AUTO_TEST_CASE(testConfigParamRetrieval, *utf::precondition(if_reachable())) diff --git a/CCDB/test/testCcdbApi_alien.cxx b/CCDB/test/testCcdbApi_alien.cxx index f11f579346524..c50f83466fe06 100644 --- a/CCDB/test/testCcdbApi_alien.cxx +++ b/CCDB/test/testCcdbApi_alien.cxx @@ -29,7 +29,7 @@ using namespace o2::ccdb; namespace utf = boost::unit_test; namespace tt = boost::test_tools; -static string ccdbUrl; +static std::string ccdbUrl; bool hostReachable = false; /** @@ -71,7 +71,7 @@ struct test_fixture { ~test_fixture() = default; CcdbApi api; - map metadata; + std::map metadata; }; // handle the case where the object comes from alien and redirect does not work with curl diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000000..9d8753a362a56 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ +This is the main repository of the ALICE Experiment Simulation, Reconstruction and Analysis Framework. + +The skills specific to developing code for this repository can be found in +the `.skills/` folder of this project. + diff --git a/CMakeLists.txt b/CMakeLists.txt index b71d05175e9e9..adecffc0f4dbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,7 +86,6 @@ include(O2AddTestRootMacro) include(O2ReportNonTestedMacros) include(O2TargetRootDictionary) include(O2DataFile) -include(O2TargetManPage) include(O2AddWorkflow) include(O2SetROOTPCMDependencies) include(O2AddHipifiedExecutable) @@ -117,10 +116,6 @@ endif() add_subdirectory(config) -add_custom_target(man ALL) -o2_target_man_page(man NAME o2) -o2_target_man_page(man NAME FairMQDevice) - # Testing and packaging only needed if we are the top level directory if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) # Documentation diff --git a/CODEOWNERS b/CODEOWNERS index 5337622522bbb..f54738e2ce4e3 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -28,13 +28,13 @@ /DataFormats/Detectors/Common @shahor02 /DataFormats/Detectors/CPV @peressounko @kharlov /DataFormats/Detectors/CTP @lietava -/DataFormats/Detectors/EMCAL @mfasDa @jokonig +/DataFormats/Detectors/EMCAL @nstrangm @jokonig /DataFormats/Detectors/FIT @jotwinow @afurs @andreasmolander @sahilupadhyaya92 -/DataFormats/Detectors/FOCAL @maxrauch @mfasDa @iarsene @matthiasrichter +/DataFormats/Detectors/FOCAL @maxrauch @iarsene @matthiasrichter /DataFormats/Detectors/GlobalTracking @shahor02 /DataFormats/Detectors/GlobalTrackingWorkflow @shahor02 /DataFormats/Detectors/HMPID @gvolpe79 -/DataFormats/Detectors/ITSMFT @fprino @mcoquet642 @mconcas @shahor02 +/DataFormats/Detectors/ITSMFT @fprino @mcoquet642 @shahor02 /DataFormats/Detectors/MUON @AliceO2Group/muon-experts @shahor02 /DataFormats/Detectors/PHOS @peressounko @kharlov /DataFormats/Detectors/Passive @sawenzel @@ -43,7 +43,7 @@ /DataFormats/Detectors/TRD @f3sch @bazinski @wille10 /DataFormats/Detectors/Upgrades @mconcas /DataFormats/Detectors/Upgrades/ITS3 @fgrosa @arossi81 -/DataFormats/Detectors/ZDC @coppedis +/DataFormats/Detectors/ZDC @coppedis @cortesep #/DataFormats/Headers #/DataFormats/Legacy @@ -58,9 +58,9 @@ /Detectors/Base @sawenzel @shahor02 /Detectors/Calibration @chiarazampolli @shahor02 /Detectors/CPV @peressounko @kharlov -/Detectors/EMCAL @mfasDa @jokonig +/Detectors/EMCAL @nstrangm @jokonig /Detectors/FIT @jotwinow @afurs @andreasmolander @sahilupadhyaya92 -/Detectors/FOCAL @maxrauch @mfasDa @iarsene @matthiasrichter +/Detectors/FOCAL @maxrauch @iarsene @matthiasrichter /Detectors/Geometry @sawenzel @shahor02 /Detectors/GlobalTracking @shahor02 /Detectors/GlobalTrackingWorkflow @shahor02 @@ -73,9 +73,9 @@ /Detectors/TPC @davidrohr @wiechula @shahor02 /Detectors/TRD @f3sch @bazinski @wille10 /Detectors/Upgrades @mconcas -/Detectors/Upgrades/ALICE3 @mconcas @njacazio +/Detectors/Upgrades/ALICE3 @mconcas @njacazio @fcolamar /Detectors/Upgrades/ITS3 @fgrosa @arossi81 @mconcas @f3sch -/Detectors/ZDC @coppedis +/Detectors/ZDC @coppedis @cortesep /Detectors/CTF @shahor02 /Detectors/Raw @shahor02 /Detectors/StrangenessTracking @mconcas @mpuccio @fmazzasc diff --git a/Common/Constants/include/CommonConstants/PhysicsConstants.h b/Common/Constants/include/CommonConstants/PhysicsConstants.h index 5f169f799eb5b..e95b4343a63d4 100644 --- a/Common/Constants/include/CommonConstants/PhysicsConstants.h +++ b/Common/Constants/include/CommonConstants/PhysicsConstants.h @@ -31,6 +31,9 @@ namespace o2::constants::physics /// \note Follow kCamelCase naming convention /// \link https://root.cern/doc/master/TPDGCode_8h.html enum Pdg { + kEta = 221, + kOmega = 223, + kEtaPrime = 331, kB0 = 511, kB0Bar = -511, kBPlus = 521, @@ -51,7 +54,10 @@ enum Pdg { kDSBar = -431, kDSStar = 433, kDS1 = 10433, + kDS1Star2700 = 30433, + kDS1Star2860 = 40433, kDS2Star = 435, + kDS3Star2860 = 437, kDStar = 413, kDStar0 = 423, kChiC1 = 20443, @@ -72,18 +78,29 @@ enum Pdg { kXiCCPlusPlus = 4422, kXiCPlus = 4232, kXiC0 = 4132, + kXiC3055Plus = 4325, + kXiC3080Plus = 4326, + kXiC3055_0 = 4315, + kXiC3080_0 = 4316, kDeuteron = 1000010020, kTriton = 1000010030, kHelium3 = 1000020030, kAlpha = 1000020040, + kLithium4 = 1000030040, kHyperTriton = 1010010030, kHyperHydrogen4 = 1010010040, kHyperHelium4 = 1010020040, kHyperHelium5 = 1010020050, - kHyperHelium4Sigma = 1110020040 + kHyperHelium4Sigma = 1110020040, + kLambda1520_Py = 102134, + kK1_1270_0 = 10313, + kK1_1270Plus = 10323 }; /// \brief Declarations of masses for additional particles +constexpr double MassEta = 0.547862; +constexpr double MassOmega = 0.78266; +constexpr double MassEtaPrime = 0.95778; constexpr double MassB0 = 5.27966; constexpr double MassB0Bar = 5.27966; constexpr double MassBPlus = 5.27934; @@ -104,7 +121,10 @@ constexpr double MassDS = 1.96835; constexpr double MassDSBar = 1.96835; constexpr double MassDSStar = 2.1122; constexpr double MassDS1 = 2.53511; +constexpr double MassDS1Star2700 = 2.714; +constexpr double MassDS1Star2860 = 2.859; constexpr double MassDS2Star = 2.5691; +constexpr double MassDS3Star2860 = 2.86; constexpr double MassDStar = 2.01026; constexpr double MassDStar0 = 2.00685; constexpr double MassChiC1 = 3.51067; @@ -125,15 +145,23 @@ constexpr double MassXiB0 = 5.7919; constexpr double MassXiCCPlusPlus = 3.62155; constexpr double MassXiCPlus = 2.46771; constexpr double MassXiC0 = 2.47044; +constexpr double MassXiC3055Plus = 3.0559; +constexpr double MassXiC3080Plus = 3.0772; +constexpr double MassXiC3055_0 = 3.059; +constexpr double MassXiC3080_0 = 3.0799; constexpr double MassDeuteron = 1.87561294257; constexpr double MassTriton = 2.80892113298; constexpr double MassHelium3 = 2.80839160743; constexpr double MassAlpha = 3.7273794066; -constexpr double MassHyperTriton = 2.99131; -constexpr double MassHyperHydrogen4 = 3.9226; -constexpr double MassHyperHelium4 = 3.9217; -constexpr double MassHyperHelium5 = 4.841; +constexpr double MassLithium4 = 3.7513; +constexpr double MassHyperTriton = 2.991134; +constexpr double MassHyperHydrogen4 = 3.922434; +constexpr double MassHyperHelium4 = 3.921728; +constexpr double MassHyperHelium5 = 4.839961; constexpr double MassHyperHelium4Sigma = 3.995; +constexpr double MassLambda1520_Py = 1.5195; +constexpr double MassK1_1270_0 = 1.253; +constexpr double MassK1_1270Plus = 1.272; /// \brief Declarations of masses for particles in ROOT PDG_t constexpr double MassDown = 0.00467; diff --git a/Common/Constants/include/CommonConstants/make_pdg_header.py b/Common/Constants/include/CommonConstants/make_pdg_header.py index 4fdfd052ff613..ccea1863771f3 100755 --- a/Common/Constants/include/CommonConstants/make_pdg_header.py +++ b/Common/Constants/include/CommonConstants/make_pdg_header.py @@ -12,7 +12,7 @@ # or submit itself to any jurisdiction. """! -@brief Generates the body of a C++ header with PDG codes and particle masses. +@brief Generates and updates the body of a C++ header with PDG codes and particle masses. @author Vít Kučera , Inha University @date 2023-09-21 """ @@ -21,9 +21,12 @@ from ctypes import c_bool from enum import Enum -import ROOT # pylint: disable=import-error +try: + import ROOT # pylint: disable=import-error + from ROOT import o2 +except (ModuleNotFoundError, ImportError) as exc: + raise OSError("O2 environment is not loaded.") from exc -name_script = os.path.basename(__file__) # Enum of PDG_t particles class PdgROOT(Enum): @@ -86,6 +89,9 @@ class PdgROOT(Enum): # Enum of additional particles class Pdg(Enum): + kEta = 221 + kOmega = 223 + kEtaPrime = 331 kB0 = 511 kB0Bar = -511 kBPlus = 521 @@ -106,7 +112,10 @@ class Pdg(Enum): kDSBar = -431 kDSStar = 433 kDS1 = 10433 + kDS1Star2700 = 30433 + kDS1Star2860 = 40433 kDS2Star = 435 + kDS3Star2860 = 437 kDStar = 413 kDStar0 = 423 kChiC1 = 20443 @@ -127,18 +136,26 @@ class Pdg(Enum): kXiCCPlusPlus = 4422 kXiCPlus = 4232 kXiC0 = 4132 + kXiC3055Plus = 4325 + kXiC3080Plus = 4326 + kXiC3055_0 = 4315 + kXiC3080_0 = 4316 kDeuteron = 1000010020 kTriton = 1000010030 kHelium3 = 1000020030 kAlpha = 1000020040 + kLithium4 = 1000030040 kHyperTriton = 1010010030 kHyperHydrogen4 = 1010010040 kHyperHelium4 = 1010020040 kHyperHelium5 = 1010020050 kHyperHelium4Sigma = 1110020040 + kLambda1520_Py = 102134 # PYTHIA code different from PDG + kK1_1270_0 = 10313 + kK1_1270Plus = 10323 -dbPdg = ROOT.o2.O2DatabasePDG +dbPdg = o2.O2DatabasePDG def mass(code): @@ -148,49 +165,109 @@ def mass(code): return dbPdg.Mass(code, success) -def declare_mass(pdg, type="double") -> str: +def declare_mass(pdg, mass_type="double") -> str: """Returns a C++ declaration of a particle mass constant.""" - return f"constexpr {type} Mass{pdg.name[1:]} = {mass(pdg.value)};\n" + return f"constexpr {mass_type} Mass{pdg.name[1:]} = {mass(pdg.value)};" -# Comment at the beginning of the output -str_block_begin = f"""// BEGINNING OF THE GENERATED BLOCK. -// DO NOT EDIT THIS BLOCK DIRECTLY! -// It has been generated by the {name_script} script. -// For modifications, edit the script and generate this block again. -""" -# Comment at the end of the output -str_block_end = """// END OF THE GENERATED BLOCK -""" -# Start of enum declarations of additional particles -str_enum_head = """/// \\brief Declarations of named PDG codes of particles missing in ROOT PDG_t -/// \\note Follow kCamelCase naming convention -/// \\link https://root.cern/doc/master/TPDGCode_8h.html -enum Pdg { -""" -# End of enum declarations of additional particles -str_enum_foot = "};\n" -# Documentation string for mass declarations of additional particles -str_mass_o2_head = """/// \\brief Declarations of masses for additional particles -""" -# Documentation string for mass declarations of PDG_t particles -str_mass_root_head = """/// \\brief Declarations of masses for particles in ROOT PDG_t -""" +def main(): + """Main function""" + + path_header = "PhysicsConstants.h" + name_script = os.path.basename(__file__) + + # Comment at the beginning of the output + block_begin = "// BEGINNING OF THE GENERATED BLOCK." + # Comment at the end of the output + block_end = "// END OF THE GENERATED BLOCK" + # Preamble with instructions + block_preamble = ( + "// DO NOT EDIT THIS BLOCK DIRECTLY!" + f"\n// It has been generated by the {name_script} script." + "\n// For modifications, edit the script and generate this block again." + ) + # Start of enum declarations of additional particles + enum_o2_head = ( + "/// \\brief Declarations of named PDG codes of particles missing in ROOT PDG_t" + "\n/// \\note Follow kCamelCase naming convention" + "\n/// \\link https://root.cern/doc/master/TPDGCode_8h.html" + "\nenum Pdg {" + ) + # End of enum declarations of additional particles + enum_o2_foot = "};" + # Documentation string for mass declarations of additional particles + mass_o2_head = "/// \\brief Declarations of masses for additional particles" + # Documentation string for mass declarations of PDG_t particles + mass_root_head = "/// \\brief Declarations of masses for particles in ROOT PDG_t" + + # Get header content before and after the generated block. + print(f'File "{path_header}" will be updated.') + try: + with open(path_header, encoding="utf-8") as file: + content_old = file.readlines() + except OSError as exc: + raise OSError(f'Failed to open file "{path_header}".') from exc + lines_header_before: list[str] = [] + lines_header_after: list[str] = [] + got_block_begin = False + got_block_end = False + for line in content_old: + line = line.strip() + if line == block_begin: + got_block_begin = True + if not got_block_begin: + lines_header_before.append(line) + if got_block_end: + lines_header_after.append(line) + if line == block_end: + got_block_end = True + if not got_block_begin: + raise ValueError("Did not find the beginning of the block.") + if not got_block_end: + raise ValueError("Did not find the end of the block.") + + # Additional particles + lines_enum_o2: list[str] = [enum_o2_head] + lines_mass_o2: list[str] = [mass_o2_head] + for pdg_o2 in Pdg: + lines_enum_o2.append(f" {pdg_o2.name} = {pdg_o2.value},") + lines_mass_o2.append(declare_mass(pdg_o2)) + lines_enum_o2[-1] = lines_enum_o2[-1][:-1] # Remove the last comma. + lines_enum_o2.append(enum_o2_foot) + + # PDG_t particles + lines_mass_root: list[str] = [mass_root_head] + for pdg_root in PdgROOT: + lines_mass_root.append(declare_mass(pdg_root)) + + # Header body + content_new = "\n".join( + ( + *lines_header_before, + block_begin, + block_preamble, + "", + *lines_enum_o2, + "", + *lines_mass_o2, + "", + *lines_mass_root, + "", + block_end, + *lines_header_after, + "", + ) + ) + # print(content_new) + + # Overwrite the input file. + try: + with open(path_header, "w", encoding="utf-8") as file: + file.write(content_new) + print(f'File "{path_header}" has been overwritten.') + except OSError as exc: + raise OSError(f'Failed to write to file "{path_header}".') from exc + -# Additional particles -str_enum = str_enum_head -str_mass_o2 = str_mass_o2_head -for c in Pdg: - str_enum += f" {c.name} = {c.value},\n" - str_mass_o2 += declare_mass(c) -str_enum = str_enum[:-2] + "\n" # Remove the last comma. -str_enum += str_enum_foot - -# PDG_t particles -str_mass_root = str_mass_root_head -for d in PdgROOT: - str_mass_root += declare_mass(d) - -# Header body -str_header = "\n".join((str_block_begin, str_enum, str_mass_o2, str_mass_root, str_block_end)) -print(str_header) +if __name__ == "__main__": + main() diff --git a/Common/DCAFitter/CMakeLists.txt b/Common/DCAFitter/CMakeLists.txt index 5c3a93aa7fa74..c0b2d0dca1026 100644 --- a/Common/DCAFitter/CMakeLists.txt +++ b/Common/DCAFitter/CMakeLists.txt @@ -22,8 +22,7 @@ o2_add_library(DCAFitter O2::DetectorsBase) o2_target_root_dictionary(DCAFitter - HEADERS include/DCAFitter/HelixHelper.h - include/DCAFitter/DCAFitterN.h + HEADERS include/DCAFitter/DCAFitterN.h include/DCAFitter/FwdDCAFitterN.h) if (OpenMP_CXX_FOUND) diff --git a/Common/DCAFitter/GPU/cuda/CMakeLists.txt b/Common/DCAFitter/GPU/cuda/CMakeLists.txt index ddc1d09445d7f..6b89207279fe0 100644 --- a/Common/DCAFitter/GPU/cuda/CMakeLists.txt +++ b/Common/DCAFitter/GPU/cuda/CMakeLists.txt @@ -22,14 +22,14 @@ o2_add_library(DCAFitterCUDA set_property(TARGET ${targetName} PROPERTY CUDA_SEPARABLE_COMPILATION ON) # add_compile_options(-lineinfo) -o2_add_test(DCAFitterNCUDA - SOURCES test/testDCAFitterNGPU.cxx - PUBLIC_LINK_LIBRARIES O2::ReconstructionDataFormats - O2::DCAFitterCUDA - O2::DCAFitter - ROOT::Core - ROOT::Physics - COMPONENT_NAME gpu - LABELS vertexing - ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage - VMCWORKDIR=${CMAKE_BINARY_DIR}/stage/${CMAKE_INSTALL_DATADIR}) \ No newline at end of file +#o2_add_test(DCAFitterNCUDA +# SOURCES test/testDCAFitterNGPU.cxx +# PUBLIC_LINK_LIBRARIES O2::ReconstructionDataFormats +# O2::DCAFitterCUDA +# O2::DCAFitter +# ROOT::Core +# ROOT::Physics +# COMPONENT_NAME gpu +# LABELS vertexing +# ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage +# VMCWORKDIR=${CMAKE_BINARY_DIR}/stage/${CMAKE_INSTALL_DATADIR}) diff --git a/Common/DCAFitter/GPU/hip/CMakeLists.txt b/Common/DCAFitter/GPU/hip/CMakeLists.txt index f62759bb6ea2c..5e7821a0b8946 100644 --- a/Common/DCAFitter/GPU/hip/CMakeLists.txt +++ b/Common/DCAFitter/GPU/hip/CMakeLists.txt @@ -21,15 +21,15 @@ o2_add_hipified_library(DCAFitterHIP PRIVATE_LINK_LIBRARIES O2::GPUTrackingHIPExternalProvider TARGETVARNAME targetNAme) -o2_add_test(DCAFitterNHIP - SOURCES ../cuda/test/testDCAFitterNGPU.cxx - PUBLIC_LINK_LIBRARIES O2::ReconstructionDataFormats - O2::DCAFitterHIP - O2::DCAFitter - ROOT::Core - ROOT::Physics - HIPIFIED test - COMPONENT_NAME gpu - LABELS vertexing - ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage - VMCWORKDIR=${CMAKE_BINARY_DIR}/stage/${CMAKE_INSTALL_DATADIR}) \ No newline at end of file +#o2_add_test(DCAFitterNHIP +# SOURCES ../cuda/test/testDCAFitterNGPU.cxx +# PUBLIC_LINK_LIBRARIES O2::ReconstructionDataFormats +# O2::DCAFitterHIP +# O2::DCAFitter +# ROOT::Core +# ROOT::Physics +# HIPIFIED test +# COMPONENT_NAME gpu +# LABELS vertexing +# ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage +# VMCWORKDIR=${CMAKE_BINARY_DIR}/stage/${CMAKE_INSTALL_DATADIR}) diff --git a/Common/DCAFitter/include/DCAFitter/DCAFitterN.h b/Common/DCAFitter/include/DCAFitter/DCAFitterN.h index 569b3ea49e515..2641dec84aed9 100644 --- a/Common/DCAFitter/include/DCAFitter/DCAFitterN.h +++ b/Common/DCAFitter/include/DCAFitter/DCAFitterN.h @@ -17,7 +17,7 @@ #ifndef _ALICEO2_DCA_FITTERN_ #define _ALICEO2_DCA_FITTERN_ -#include "DCAFitter/HelixHelper.h" +#include "ReconstructionDataFormats/HelixHelper.h" #include "DetectorsBase/Propagator.h" #include "MathUtils/Cartesian.h" #include "ReconstructionDataFormats/Track.h" @@ -110,11 +110,11 @@ class DCAFitterN using MatSymND = o2::math_utils::SMatrix>; using MatStdND = o2::math_utils::SMatrix>; using TrackCoefVtx = MatStd3D; - using ArrTrack = o2::gpu::gpustd::array; // container for prongs (tracks) at single vertex cand. - using ArrTrackCovI = o2::gpu::gpustd::array; // container for inv.cov.matrices at single vertex cand. - using ArrTrCoef = o2::gpu::gpustd::array; // container of TrackCoefVtx coefficients at single vertex cand. - using ArrTrDer = o2::gpu::gpustd::array; // container of Track 1st and 2nd derivative over their X param - using ArrTrPos = o2::gpu::gpustd::array; // container of Track positions + using ArrTrack = std::array; // container for prongs (tracks) at single vertex cand. + using ArrTrackCovI = std::array; // container for inv.cov.matrices at single vertex cand. + using ArrTrCoef = std::array; // container of TrackCoefVtx coefficients at single vertex cand. + using ArrTrDer = std::array; // container of Track 1st and 2nd derivative over their X param + using ArrTrPos = std::array; // container of Track positions public: enum BadCovPolicy : uint8_t { // if encountering non-positive defined cov. matrix, the choice is: @@ -142,6 +142,8 @@ class DCAFitterN FailInv2ndDeriv, // inversion of 2nd derivatives failed FailCorrTracks, // correction of tracks to updated x failed FailCloserAlt, // alternative PCA is closer + // + NStatusesDefined }; static constexpr int getNProngs() { return N; } @@ -158,7 +160,7 @@ class DCAFitterN GPUd() const auto getPCACandidatePos(int cand = 0) const { const auto& vd = mPCA[mOrder[cand]]; - return o2::gpu::gpustd::array{static_cast(vd[0]), static_cast(vd[1]), static_cast(vd[2])}; + return std::array{static_cast(vd[0]), static_cast(vd[1]), static_cast(vd[2])}; } ///< return position of quality-ordered candidate in the internal structures @@ -213,7 +215,7 @@ class DCAFitterN GPUd() MatSym3D calcPCACovMatrix(int cand = 0) const; - o2::gpu::gpustd::array calcPCACovMatrixFlat(int cand = 0) const + std::array calcPCACovMatrixFlat(int cand = 0) const { auto m = calcPCACovMatrix(cand); return {static_cast(m(0, 0)), static_cast(m(1, 0)), static_cast(m(1, 1)), static_cast(m(2, 0)), static_cast(m(2, 1)), static_cast(m(2, 2))}; @@ -364,39 +366,39 @@ class DCAFitterN private: // vectors of 1st derivatives of track local residuals over X parameters - o2::gpu::gpustd::array, N> mDResidDx; + std::array, N> mDResidDx; // vectors of 1nd derivatives of track local residuals over X parameters // (cross-derivatives DR/(dx_j*dx_k) = 0 for j!=k, therefore the hessian is diagonal) - o2::gpu::gpustd::array, N> mD2ResidDx2; + std::array, N> mD2ResidDx2; VecND mDChi2Dx; // 1st derivatives of chi2 over tracks X params MatSymND mD2Chi2Dx2; // 2nd derivatives of chi2 over tracks X params (symmetric matrix) MatSymND mCosDif; // matrix with cos(alp_j-alp_i) for j mOrigTrPtr; - o2::gpu::gpustd::array mTrAux; // Aux track info for each track at each cand. vertex - CrossInfo mCrossings; // info on track crossing - - o2::gpu::gpustd::array mTrcEInv; // errors for each track at each cand. vertex - o2::gpu::gpustd::array mCandTr; // tracks at each cond. vertex (Note: Errors are at seed XY point) - o2::gpu::gpustd::array mTrCFVT; // TrackCoefVtx for each track at each cand. vertex - o2::gpu::gpustd::array mTrDer; // Track derivativse - o2::gpu::gpustd::array mTrPos; // Track positions - o2::gpu::gpustd::array mTrRes; // Track residuals - o2::gpu::gpustd::array mPCA; // PCA for each vertex candidate - o2::gpu::gpustd::array mChi2 = {0}; // Chi2 at PCA candidate - o2::gpu::gpustd::array mNIters; // number of iterations for each seed - o2::gpu::gpustd::array mTrPropDone{}; // Flag that the tracks are fully propagated to PCA - o2::gpu::gpustd::array mPropFailed{}; // Flag that some propagation failed for this PCA candidate + std::array mOrigTrPtr; + std::array mTrAux; // Aux track info for each track at each cand. vertex + CrossInfo mCrossings; // info on track crossing + + std::array mTrcEInv; // errors for each track at each cand. vertex + std::array mCandTr; // tracks at each cond. vertex (Note: Errors are at seed XY point) + std::array mTrCFVT; // TrackCoefVtx for each track at each cand. vertex + std::array mTrDer; // Track derivativse + std::array mTrPos; // Track positions + std::array mTrRes; // Track residuals + std::array mPCA; // PCA for each vertex candidate + std::array mChi2 = {0}; // Chi2 at PCA candidate + std::array mNIters; // number of iterations for each seed + std::array mTrPropDone{}; // Flag that the tracks are fully propagated to PCA + std::array mPropFailed{}; // Flag that some propagation failed for this PCA candidate LogLogThrottler mLoggerBadCov{}; LogLogThrottler mLoggerBadInv{}; LogLogThrottler mLoggerBadProp{}; MatSym3D mWeightInv; // inverse weight of single track, [sum{M^T E M}]^-1 in EQ.T - o2::gpu::gpustd::array mOrder{0}; + std::array mOrder{0}; int mCurHyp = 0; int mCrossIDCur = 0; int mCrossIDAlt = -1; BadCovPolicy mBadCovPolicy{BadCovPolicy::Discard}; // what to do in case of non-pos-def. cov. matrix, see BadCovPolicy enum - o2::gpu::gpustd::array mFitStatus{}; // fit status of each hypothesis fit + std::array mFitStatus{}; // fit status of each hypothesis fit bool mAllowAltPreference = true; // if the fit converges to alternative PCA seed, abandon the current one bool mUseAbsDCA = false; // use abs. distance minimization rather than chi2 bool mWeightedFinalPCA = false; // recalculate PCA as a cov-matrix weighted mean, even if absDCA method was used @@ -657,7 +659,7 @@ template GPUd() void DCAFitterN::calcChi2Derivatives() { //< calculate 1st and 2nd derivatives of wighted DCA (chi2) over track parameters X, see EQ.Chi2 in the ref - o2::gpu::gpustd::array, N> covIDrDx; // tempory vectors of covI_j * dres_j/dx_i + std::array, N> covIDrDx; // tempory vectors of covI_j * dres_j/dx_i // chi2 1st derivative for (int i = N; i--;) { @@ -816,6 +818,7 @@ GPUd() o2::math_utils::SMatrix::minimizeChi2() } if (mMaxDZIni > 0 && !roughDZCut()) { // apply rough cut on tracks Z difference - mFitStatus[mCurHyp] = FitStatus::RejTrackX; + mFitStatus[mCurHyp] = FitStatus::RejTrackRoughZ; return false; } @@ -1063,7 +1066,7 @@ GPUd() bool DCAFitterN::minimizeChi2NoErr() setTrackPos(mTrPos[mCurHyp][i], mCandTr[mCurHyp][i]); // prepare positions } if (mMaxDZIni > 0 && !roughDZCut()) { // apply rough cut on tracks Z difference - mFitStatus[mCurHyp] = FitStatus::RejTrackX; + mFitStatus[mCurHyp] = FitStatus::RejTrackRoughZ; return false; } @@ -1175,13 +1178,13 @@ GPUd() o2::track::TrackParCov DCAFitterN::createParentTrackParCov(in { const auto& trP = getTrack(0, cand); const auto& trN = getTrack(1, cand); - o2::gpu::gpustd::array covV = {0.}; - o2::gpu::gpustd::array pvecV = {0.}; + std::array covV = {0.}; + std::array pvecV = {0.}; int q = 0; for (int it = 0; it < N; it++) { const auto& trc = getTrack(it, cand); - o2::gpu::gpustd::array pvecT = {0.}; - o2::gpu::gpustd::array covT = {0.}; + std::array pvecT = {0.}; + std::array covT = {0.}; trc.getPxPyPzGlo(pvecT); trc.getCovXYZPxPyPzGlo(covT); constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component @@ -1210,18 +1213,18 @@ GPUd() o2::track::TrackPar DCAFitterN::createParentTrackPar(int cand const auto& trP = getTrack(0, cand); const auto& trN = getTrack(1, cand); const auto& wvtx = getPCACandidate(cand); - o2::gpu::gpustd::array pvecV = {0.}; + std::array pvecV = {0.}; int q = 0; for (int it = 0; it < N; it++) { const auto& trc = getTrack(it, cand); - o2::gpu::gpustd::array pvecT = {0.}; + std::array pvecT = {0.}; trc.getPxPyPzGlo(pvecT); for (int i = 0; i < 3; i++) { pvecV[i] += pvecT[i]; } q += trc.getCharge(); } - const o2::gpu::gpustd::array vertex = {(float)wvtx[0], (float)wvtx[1], (float)wvtx[2]}; + const std::array vertex = {(float)wvtx[0], (float)wvtx[1], (float)wvtx[2]}; return o2::track::TrackPar(vertex, pvecV, q, sectorAlpha); } diff --git a/Common/DCAFitter/include/DCAFitter/FwdDCAFitterN.h b/Common/DCAFitter/include/DCAFitter/FwdDCAFitterN.h index cd1742e24fa72..d5bc6631575af 100644 --- a/Common/DCAFitter/include/DCAFitter/FwdDCAFitterN.h +++ b/Common/DCAFitter/include/DCAFitter/FwdDCAFitterN.h @@ -20,7 +20,7 @@ #include "MathUtils/Cartesian.h" #include "ReconstructionDataFormats/TrackFwd.h" #include "ReconstructionDataFormats/Track.h" -#include "DCAFitter/HelixHelper.h" +#include "ReconstructionDataFormats/HelixHelper.h" #include #include "DetectorsBase/Propagator.h" #include "DetectorsBase/GeometryManager.h" diff --git a/Common/DCAFitter/src/DCAFitterLinkDef.h b/Common/DCAFitter/src/DCAFitterLinkDef.h index 3589ffe559e96..6883369c1b9b6 100644 --- a/Common/DCAFitter/src/DCAFitterLinkDef.h +++ b/Common/DCAFitter/src/DCAFitterLinkDef.h @@ -18,9 +18,6 @@ #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::track::TrackAuxPar + ; -#pragma link C++ class o2::track::CrossInfo + ; - #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&); diff --git a/Common/Field/include/Field/MagFieldFast.h b/Common/Field/include/Field/MagFieldFast.h index acff8f528ad06..ae6431a477923 100644 --- a/Common/Field/include/Field/MagFieldFast.h +++ b/Common/Field/include/Field/MagFieldFast.h @@ -57,7 +57,7 @@ class MagFieldFast bool Field(const math_utils::Point3D 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 xyz, double& b) const; + bool GetBcomp(EDim comp, const math_utils::Point3D xyz, double& b) const; bool GetBcomp(EDim comp, const math_utils::Point3D xyz, float& b) const; bool GetBx(const double xyz[3], double& bx) const { return GetBcomp(kX, xyz, bx); } @@ -66,6 +66,8 @@ class MagFieldFast bool GetBy(const float xyz[3], float& by) const { return GetBcomp(kY, xyz, by); } bool GetBz(const double xyz[3], double& bz) const { return GetBcomp(kZ, xyz, bz); } bool GetBz(const float xyz[3], float& bz) const { return GetBcomp(kZ, xyz, bz); } + bool GetBz(const math_utils::Point3D xyz, double& bz) const { return GetBcomp(kZ, xyz, bz); } + bool GetBz(const math_utils::Point3D xyz, float& bz) const { return GetBcomp(kZ, xyz, bz); } void setFactorSol(float v = 1.f) { mFactorSol = v; } float getFactorSol() const { return mFactorSol; } diff --git a/Common/Field/src/MagFieldFast.cxx b/Common/Field/src/MagFieldFast.cxx index 5caad34d56dd4..9735d0c711fa3 100644 --- a/Common/Field/src/MagFieldFast.cxx +++ b/Common/Field/src/MagFieldFast.cxx @@ -16,12 +16,10 @@ #include "Field/MagFieldFast.h" #include -#ifndef GPUCA_GPUCODE_DEVICE #include #include #include using namespace std; -#endif using namespace o2::field; @@ -145,7 +143,7 @@ bool MagFieldFast::GetBcomp(EDim comp, const double xyz[3], double& b) const } //_______________________________________________________________________ -bool MagFieldFast::GetBcomp(EDim comp, const math_utils::Point3D xyz, double& b) const +bool MagFieldFast::GetBcomp(EDim comp, const math_utils::Point3D xyz, double& b) const { // get field int zSeg, rSeg, quadrant; diff --git a/Common/ML/include/ML/3rdparty/GPUORTFloat16.h b/Common/ML/include/ML/3rdparty/GPUORTFloat16.h index 3bf2f465b2a35..75e146d872cd1 100644 --- a/Common/ML/include/ML/3rdparty/GPUORTFloat16.h +++ b/Common/ML/include/ML/3rdparty/GPUORTFloat16.h @@ -568,9 +568,11 @@ GPUdi() uint16_t BFloat16Impl::ToUint16Impl(float v) noexcept template GPUdi() float BFloat16Impl::ToFloatImpl() const noexcept { +#ifndef __FAST_MATH__ if (IsNaN()) { return o2::gpu::CAMath::QuietNaN(); } +#endif float result; char* const first = reinterpret_cast(&result); char* const second = first + sizeof(uint16_t); diff --git a/Common/ML/include/ML/OrtInterface.h b/Common/ML/include/ML/OrtInterface.h index b4f40f3f5c694..987ce8fb4d6dd 100644 --- a/Common/ML/include/ML/OrtInterface.h +++ b/Common/ML/include/ML/OrtInterface.h @@ -34,10 +34,7 @@ struct MemoryInfo; struct Env; } // namespace Ort -namespace o2 -{ - -namespace ml +namespace o2::ml { class OrtModel @@ -45,19 +42,16 @@ class OrtModel public: // Constructors & destructors - OrtModel() = default; - OrtModel(std::unordered_map optionsMap) { init(optionsMap); } - void init(std::unordered_map optionsMap) - { - initOptions(optionsMap); - initEnvironment(); - } - virtual ~OrtModel() = default; + OrtModel(); + OrtModel(std::unordered_map optionsMap); + void init(std::unordered_map optionsMap); + virtual ~OrtModel(); // General purpose void initOptions(std::unordered_map optionsMap); void initEnvironment(); void initSession(); + void initSessionFromBuffer(const char* buffer, size_t bufferSize); void memoryOnDevice(int32_t = 0); bool isInitialized() { return mInitialized; } void resetSession(); @@ -113,7 +107,7 @@ class OrtModel private: // ORT variables -> need to be hidden as pImpl struct OrtVariables; - OrtVariables* mPImplOrt; + std::unique_ptr mPImplOrt; // Input & Output specifications of the loaded network std::vector mInputNamesChar, mOutputNamesChar; @@ -123,7 +117,7 @@ class OrtModel int32_t mInputsTotal = 0, mOutputsTotal = 0; // Total number of inputs and outputs // Environment settings - bool mInitialized = false; + bool mInitialized = false, mDeterministicMode = false; std::string mModelPath, mEnvName = "", mDeviceType = "CPU", mThreadAffinity = ""; // device options should be cpu, rocm, migraphx, cuda int32_t mIntraOpNumThreads = 1, mInterOpNumThreads = 1, mDeviceId = -1, mEnableProfiling = 0, mLoggingLevel = 0, mAllocateDeviceMemory = 0, mEnableOptimizations = 0; @@ -131,8 +125,6 @@ class OrtModel std::string printShape(const std::vector>&, std::vector&); }; -} // namespace ml - -} // namespace o2 +} // namespace o2::ml #endif // O2_ML_ORTINTERFACE_H diff --git a/Common/ML/src/OrtInterface.cxx b/Common/ML/src/OrtInterface.cxx index df7f0a2deba82..8f88ab18dacbd 100644 --- a/Common/ML/src/OrtInterface.cxx +++ b/Common/ML/src/OrtInterface.cxx @@ -27,11 +27,20 @@ namespace o2 namespace ml { +OrtModel::OrtModel() = default; +OrtModel::OrtModel(std::unordered_map optionsMap) { init(optionsMap); } +OrtModel::~OrtModel() = default; +void OrtModel::init(std::unordered_map optionsMap) +{ + initOptions(optionsMap); + initEnvironment(); +} + struct OrtModel::OrtVariables { // The actual implementation is hidden in the .cxx file // ORT runtime objects Ort::RunOptions runOptions; - std::shared_ptr env = nullptr; - std::shared_ptr session = nullptr; ///< ONNX session + std::unique_ptr env = nullptr; + std::unique_ptr session = nullptr; ///< ONNX session Ort::SessionOptions sessionOptions; Ort::AllocatorWithDefaultOptions allocator; Ort::MemoryInfo memoryInfo = Ort::MemoryInfo("Cpu", OrtAllocatorType::OrtDeviceAllocator, 0, OrtMemType::OrtMemTypeDefault); @@ -41,11 +50,11 @@ struct OrtModel::OrtVariables { // The actual implementation is hidden in the .c // General purpose void OrtModel::initOptions(std::unordered_map optionsMap) { - mPImplOrt = new OrtVariables(); + mPImplOrt = std::make_unique(); // Load from options map if (!optionsMap.contains("model-path")) { - LOG(fatal) << "(ORT) Model path cannot be empty!"; + LOG(fatal) << "(ORT) Model path must be contained in options map!"; } if (!optionsMap["model-path"].empty()) { @@ -59,6 +68,7 @@ void OrtModel::initOptions(std::unordered_map optionsM mEnableProfiling = (optionsMap.contains("enable-profiling") ? std::stoi(optionsMap["enable-profiling"]) : 0); mEnableOptimizations = (optionsMap.contains("enable-optimizations") ? std::stoi(optionsMap["enable-optimizations"]) : 0); mEnvName = (optionsMap.contains("onnx-environment-name") ? optionsMap["onnx-environment-name"] : "onnx_model_inference"); + mDeterministicMode = (optionsMap.contains("deterministic-compute") ? std::stoi(optionsMap["deterministic-compute"]) : 0); if (mDeviceType == "CPU") { (mPImplOrt->sessionOptions).SetIntraOpNumThreads(mIntraOpNumThreads); @@ -90,6 +100,10 @@ void OrtModel::initOptions(std::unordered_map optionsM (mPImplOrt->sessionOptions).DisableProfiling(); } + if (mDeterministicMode > 0) { + (mPImplOrt->sessionOptions).AddConfigEntry("session_options.use_deterministic_compute", "1"); + } + (mPImplOrt->sessionOptions).SetGraphOptimizationLevel(GraphOptimizationLevel(mEnableOptimizations)); (mPImplOrt->sessionOptions).SetLogSeverityLevel(OrtLoggingLevel(mLoggingLevel)); @@ -101,7 +115,7 @@ void OrtModel::initOptions(std::unordered_map optionsM void OrtModel::initEnvironment() { - mPImplOrt->env = std::make_shared( + mPImplOrt->env = std::make_unique( OrtLoggingLevel(mLoggingLevel), (mEnvName.empty() ? "ORT" : mEnvName.c_str()), // Integrate ORT logging into Fairlogger @@ -124,12 +138,30 @@ void OrtModel::initEnvironment() (mPImplOrt->env)->DisableTelemetryEvents(); // Disable telemetry events } +void OrtModel::initSessionFromBuffer(const char* buffer, size_t bufferSize) +{ + mPImplOrt->sessionOptions.AddConfigEntry("session.load_model_format", "ONNX"); + mPImplOrt->sessionOptions.AddConfigEntry("session.use_ort_model_bytes_directly", "1"); + + mPImplOrt->session = std::make_unique(*mPImplOrt->env, + buffer, + bufferSize, + mPImplOrt->sessionOptions); + mPImplOrt->ioBinding = std::make_unique(*mPImplOrt->session); + + setIO(); + + if (mLoggingLevel < 2) { + LOG(info) << "(ORT) Model loaded successfully from buffer! (inputs: " << printShape(mInputShapes, mInputNames) << ", outputs: " << printShape(mOutputShapes, mInputNames) << ")"; + } +} + void OrtModel::initSession() { if (mAllocateDeviceMemory) { memoryOnDevice(mDeviceId); } - mPImplOrt->session = std::make_shared(*mPImplOrt->env, mModelPath.c_str(), mPImplOrt->sessionOptions); + mPImplOrt->session = std::make_unique(*mPImplOrt->env, mModelPath.c_str(), mPImplOrt->sessionOptions); mPImplOrt->ioBinding = std::make_unique(*mPImplOrt->session); setIO(); @@ -147,12 +179,12 @@ void OrtModel::memoryOnDevice(int32_t deviceIndex) (mPImplOrt->sessionOptions).AddConfigEntry("session.use_env_allocators", "1"); // This should enable to use the volatile memory allocation defined in O2/GPU/GPUTracking/TPCClusterFinder/GPUTPCNNClusterizerHost.cxx; not working yet: ONNX still assigns new memory at init time (mPImplOrt->sessionOptions).AddConfigEntry("session_options.enable_cpu_mem_arena", "0"); // This should enable to use the volatile memory allocation defined in O2/GPU/GPUTracking/TPCClusterFinder/GPUTPCNNClusterizerHost.cxx; not working yet: ONNX still assigns new memory at init time // Arena memory shrinkage comes at performance cost - /// For now prefer to use single allocation, enabled by O2/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu -> SetONNXGPUStream -> rocm_options.arena_extend_strategy = 0; - // (mPImplOrt->runOptions).AddConfigEntry("memory.enable_memory_arena_shrinkage", ("gpu:" + std::to_string(deviceIndex)).c_str()); // See kOrtRunOptionsConfigEnableMemoryArenaShrinkage, https://github.com/microsoft/onnxruntime/blob/90c263f471bbce724e77d8e62831d3a9fa838b2f/include/onnxruntime/core/session/onnxruntime_run_options_config_keys.h#L27 + // For now prefer to use single allocation, enabled by O2/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu -> SetONNXGPUStream -> rocm_options.arena_extend_strategy = 0; + (mPImplOrt->runOptions).AddConfigEntry("memory.enable_memory_arena_shrinkage", ("gpu:" + std::to_string(deviceIndex)).c_str()); // See kOrtRunOptionsConfigEnableMemoryArenaShrinkage, https://github.com/microsoft/onnxruntime/blob/90c263f471bbce724e77d8e62831d3a9fa838b2f/include/onnxruntime/core/session/onnxruntime_run_options_config_keys.h#L27 std::string dev_mem_str = ""; if (mDeviceType == "ROCM") { - dev_mem_str = "Hip"; + dev_mem_str = "HipPinned"; } if (mDeviceType == "CUDA") { dev_mem_str = "Cuda"; @@ -166,7 +198,7 @@ void OrtModel::memoryOnDevice(int32_t deviceIndex) void OrtModel::resetSession() { - mPImplOrt->session = std::make_shared(*(mPImplOrt->env), mModelPath.c_str(), mPImplOrt->sessionOptions); + mPImplOrt->session = std::make_unique(*(mPImplOrt->env), mModelPath.c_str(), mPImplOrt->sessionOptions); } // Getters @@ -252,7 +284,7 @@ void OrtModel::setIO() void OrtModel::setEnv(Ort::Env* env) { - mPImplOrt->env = std::shared_ptr(env); + mPImplOrt->env.reset(env); } // Inference @@ -278,9 +310,9 @@ std::vector OrtModel::inference(std::vector& input) return outputValuesVec; } -template std::vector OrtModel::inference(std::vector&); -template std::vector OrtModel::inference(std::vector&); -template std::vector OrtModel::inference(std::vector&); +template std::vector o2::ml::OrtModel::inference(std::vector&); +template std::vector o2::ml::OrtModel::inference(std::vector&); +template std::vector o2::ml::OrtModel::inference(std::vector&); template void OrtModel::inference(I* input, int64_t input_size, O* output) @@ -308,6 +340,14 @@ void OrtModel::inference(I* input, int64_t input_size, O* output) (mPImplOrt->ioBinding)->BindOutput(mOutputNames[0].c_str(), outputTensor); (mPImplOrt->session)->Run(mPImplOrt->runOptions, *mPImplOrt->ioBinding); + // mPImplOrt->session->Run( + // mPImplOrt->runOptions, + // mInputNamesChar.data(), + // &inputTensor, + // mInputNamesChar.size(), + // mOutputNamesChar.data(), + // &outputTensor, + // mOutputNamesChar.size()); } template void OrtModel::inference(OrtDataType::Float16_t*, int64_t, OrtDataType::Float16_t*); @@ -427,10 +467,7 @@ template std::vector OrtModel::inferencesession->EndProfiling(); - // } - LOG(info) << "(ORT) Size of mPImplOrt: " << sizeof(*mPImplOrt) << " bytes"; + mPImplOrt.reset(); } // private diff --git a/Common/MathUtils/include/MathUtils/BetheBlochAleph.h b/Common/MathUtils/include/MathUtils/BetheBlochAleph.h new file mode 100644 index 0000000000000..bd72faffb0503 --- /dev/null +++ b/Common/MathUtils/include/MathUtils/BetheBlochAleph.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_COMMON_BETHEBLOCH_H_ +#define AliceO2_COMMON_BETHEBLOCH_H_ + +#include "GPUCommonDef.h" +#include "GPUCommonMath.h" + +namespace o2::common +{ + +template +GPUdi() T BetheBlochAleph(T bg, T kp1, T kp2, T kp3, T kp4, T kp5) +{ + T beta = bg / o2::gpu::GPUCommonMath::Sqrt(static_cast(1.) + bg * bg); + + T aa = o2::gpu::GPUCommonMath::Pow(beta, kp4); + T bb = o2::gpu::GPUCommonMath::Pow(static_cast(1.) / bg, kp5); + bb = o2::gpu::GPUCommonMath::Log(kp3 + bb); + + return (kp2 - aa - bb) * kp1 / aa; +} + +} // namespace o2::common + +#endif diff --git a/Common/MathUtils/include/MathUtils/Cartesian.h b/Common/MathUtils/include/MathUtils/Cartesian.h index 9b917707835a6..d7e421ecd965b 100644 --- a/Common/MathUtils/include/MathUtils/Cartesian.h +++ b/Common/MathUtils/include/MathUtils/Cartesian.h @@ -284,25 +284,15 @@ GPUdi() SMatrix> Similarity(const SMatrix +struct is_forced_trivially_copyable; -/// Defining Point3D explicitly as trivially copyable -/// -/// std::is_trivially_copyable> fails because the class -/// implements a copy constructor, although it does not much more than the default copy -/// constructor. We need Point3D to fulfill the condition in order to make types -/// inheriting from it or using it as member can be safely detected as messageable. -/// -/// We believe that Point3D is messageable and explicitly specialize the type trait. -/// There is a unit test for checking trivial copy -/// This is a workaround, we will also make suggestions to fix the cause in ROOT itself -/// TODO: delete once it is fixed in ROOT template -struct is_trivially_copyable> : std::true_type { +struct is_forced_trivially_copyable> : std::true_type { }; -} // namespace std +} // namespace o2::framework #endif // Disable for GPU #endif diff --git a/Common/MathUtils/include/MathUtils/SMatrixGPU.h b/Common/MathUtils/include/MathUtils/SMatrixGPU.h index 5ecdcd75a9906..8158a93666a92 100644 --- a/Common/MathUtils/include/MathUtils/SMatrixGPU.h +++ b/Common/MathUtils/include/MathUtils/SMatrixGPU.h @@ -25,11 +25,13 @@ #define ALICEO2_SMATRIX_GPU_H #include "GPUCommonDef.h" -#include "GPUCommonArray.h" #include "GPUCommonMath.h" #include "GPUCommonAlgorithm.h" #include "GPUCommonLogger.h" -#include "GPUCommonTypeTraits.h" +#ifndef GPUCA_GPUCODE_DEVICE +#include +#include +#endif namespace o2::math_utils::detail { @@ -281,14 +283,14 @@ struct make_indices : make_indices_impl<0, indices<>, N> { }; template -constexpr auto do_make(F f, indices) -> gpu::gpustd::array +constexpr auto do_make(F f, indices) -> std::array { - gpu::gpustd::array retarr = {f(I0 + I)...}; + std::array retarr = {f(I0 + I)...}; return retarr; } template -constexpr auto make(F f) -> gpu::gpustd::array +constexpr auto make(F f) -> std::array { return do_make(f, typename make_indices::type()); } diff --git a/Common/MathUtils/include/MathUtils/detail/Bracket.h b/Common/MathUtils/include/MathUtils/detail/Bracket.h index 25d0dbd1d0a6e..2da6949c4a6f8 100644 --- a/Common/MathUtils/include/MathUtils/detail/Bracket.h +++ b/Common/MathUtils/include/MathUtils/detail/Bracket.h @@ -17,7 +17,7 @@ #define ALICEO2_BRACKET_H #include -#ifndef GPUCA_ALIGPUCODE +#ifndef GPUCA_GPUCODE_DEVICE #include #include #endif @@ -76,7 +76,7 @@ class Bracket Relation isOutside(T t, T tErr) const; Relation isOutside(T t) const; -#ifndef GPUCA_ALIGPUCODE +#ifndef GPUCA_GPUCODE_DEVICE std::string asString() const; #endif @@ -247,7 +247,7 @@ inline typename Bracket::Relation Bracket::isOutside(T t) const return t < mMin ? Below : (t > mMax ? Above : Inside); } -#ifndef GPUCA_ALIGPUCODE +#ifndef GPUCA_GPUCODE_DEVICE template std::string Bracket::asString() const { diff --git a/Common/MathUtils/include/MathUtils/detail/basicMath.h b/Common/MathUtils/include/MathUtils/detail/basicMath.h index 3565764435a68..1abe6ee878c39 100644 --- a/Common/MathUtils/include/MathUtils/detail/basicMath.h +++ b/Common/MathUtils/include/MathUtils/detail/basicMath.h @@ -16,14 +16,15 @@ #ifndef MATHUTILS_INCLUDE_MATHUTILS_DETAIL_BASICMATH_H_ #define MATHUTILS_INCLUDE_MATHUTILS_DETAIL_BASICMATH_H_ +#include "GPUCommonDef.h" +#include "GPUCommonMath.h" +#include "CommonConstants/MathConstants.h" + #ifndef GPUCA_GPUCODE_DEVICE #include #include +#include #endif -#include "GPUCommonArray.h" -#include "GPUCommonDef.h" -#include "GPUCommonMath.h" -#include "CommonConstants/MathConstants.h" namespace o2 { @@ -130,4 +131,4 @@ GPUdi() double log(double x) } // namespace math_utils } // namespace o2 -#endif /* MATHUTILS_INCLUDE_MATHUTILS_DETAIL_BASICMATH_H_ */ \ No newline at end of file +#endif /* MATHUTILS_INCLUDE_MATHUTILS_DETAIL_BASICMATH_H_ */ diff --git a/Common/MathUtils/include/MathUtils/detail/trigonometric.h b/Common/MathUtils/include/MathUtils/detail/trigonometric.h index 462affdceb17f..457210202ca54 100644 --- a/Common/MathUtils/include/MathUtils/detail/trigonometric.h +++ b/Common/MathUtils/include/MathUtils/detail/trigonometric.h @@ -16,16 +16,17 @@ #ifndef MATHUTILS_INCLUDE_MATHUTILS_DETAIL_TRIGONOMETRIC_H_ #define MATHUTILS_INCLUDE_MATHUTILS_DETAIL_TRIGONOMETRIC_H_ -#ifndef GPUCA_GPUCODE_DEVICE -#include -#include -#endif -#include "GPUCommonArray.h" #include "GPUCommonDef.h" #include "GPUCommonMath.h" #include "CommonConstants/MathConstants.h" #include "MathUtils/detail/basicMath.h" +#ifndef GPUCA_GPUCODE_DEVICE +#include +#include +#include +#endif + namespace o2 { namespace math_utils @@ -156,7 +157,7 @@ GPUhdi() std::tuple rotateZInv(T xG, T yG, T snAlp, T csAlp) #endif template -GPUhdi() void rotateZ(gpu::gpustd::array& xy, T alpha) +GPUhdi() void rotateZ(std::array& xy, T alpha) { // transforms vector in tracking frame alpha to global frame T sin, cos; diff --git a/Common/MathUtils/include/MathUtils/fit.h b/Common/MathUtils/include/MathUtils/fit.h index 00c39486a4ba0..cd5cb415070d3 100644 --- a/Common/MathUtils/include/MathUtils/fit.h +++ b/Common/MathUtils/include/MathUtils/fit.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "Rtypes.h" #include "TLinearFitter.h" @@ -69,9 +70,9 @@ TFitResultPtr fit(const size_t nBins, const T* arr, const T xMin, const T xMax, // create an empty TFitResult std::shared_ptr tfr(new TFitResult()); // create the fitter from an empty fit result - //std::shared_ptr fitter(new ROOT::Fit::Fitter(std::static_pointer_cast(tfr) ) ); + // std::shared_ptr fitter(new ROOT::Fit::Fitter(std::static_pointer_cast(tfr) ) ); ROOT::Fit::Fitter fitter(tfr); - //ROOT::Fit::FitConfig & fitConfig = fitter->Config(); + // ROOT::Fit::FitConfig & fitConfig = fitter->Config(); const double binWidth = double(xMax - xMin) / double(nBins); @@ -225,8 +226,8 @@ bool medmadGaus(size_t nBins, const T* arr, const T xMin, const T xMax, std::arr /// -1: only one point has been used for the calculation - center of gravity was uesed for calculation /// -4: invalid result!! /// -//template -//Double_t fitGaus(const size_t nBins, const T *arr, const T xMin, const T xMax, std::vector& param); +// template +// Double_t fitGaus(const size_t nBins, const T *arr, const T xMin, const T xMax, std::vector& param); template Double_t fitGaus(const size_t nBins, const T* arr, const T xMin, const T xMax, std::vector& param) { @@ -301,7 +302,7 @@ Double_t fitGaus(const size_t nBins, const T* arr, const T xMin, const T xMax, s Double_t chi2 = 0; if (npoints >= 3) { if (npoints == 3) { - //analytic calculation of the parameters for three points + // analytic calculation of the parameters for three points A.Invert(); TMatrixD res(1, 3); res.Mult(A, b); @@ -334,7 +335,7 @@ Double_t fitGaus(const size_t nBins, const T* arr, const T xMin, const T xMax, s } if (npoints == 2) { - //use center of gravity for 2 points + // use center of gravity for 2 points meanCOG /= sumCOG; rms2COG /= sumCOG; param[0] = max; @@ -524,7 +525,7 @@ R median(std::vector v) auto n = v.size() / 2; nth_element(v.begin(), v.begin() + n, v.end()); auto med = R{v[n]}; - if (!(v.size() & 1)) { //If the set size is even + if (!(v.size() & 1)) { // If the set size is even auto max_it = max_element(v.begin(), v.begin() + n); med = R{(*max_it + med) / 2.0}; } @@ -788,6 +789,169 @@ T MAD2Sigma(int np, T* y) return median * 1.4826; // convert to Gaussian sigma } +/// \return returns the index of the closest timestamps to the left and right of the given timestamp +/// \param timestamps vector of timestamps +/// \param timestamp the timestamp to find the closest timestamps for +template +std::optional> findClosestIndices(const std::vector& timestamps, DataTime timestamp) +{ + if (timestamps.empty()) { + LOGP(warning, "Timestamp vector is empty!"); + return std::nullopt; + } + + if (timestamp <= timestamps.front()) { + return std::pair{0, 0}; + } else if (timestamp >= timestamps.back()) { + return std::pair{timestamps.size() - 1, timestamps.size() - 1}; + } + + const auto it = std::lower_bound(timestamps.begin(), timestamps.end(), timestamp); + const size_t idx = std::distance(timestamps.begin(), it); + const auto prevTimestamp = timestamps[idx - 1]; + const auto nextTimestamp = timestamps[idx]; + return std::pair{(idx - 1), idx}; +} + +struct RollingStats { + RollingStats() = default; + RollingStats(const int nValues) + { + median.resize(nValues); + std.resize(nValues); + nPoints.resize(nValues); + closestDistanceL.resize(nValues); + closestDistanceR.resize(nValues); + } + + std::vector median; ///< median of rolling data + std::vector std; ///< std of rolling data + std::vector nPoints; ///< number of points used for the calculation + std::vector closestDistanceL; ///< distance of closest point to the left + std::vector closestDistanceR; ///< distance of closest point to the right + + ClassDefNV(RollingStats, 1); +}; + +/// \brief calculates the rolling statistics of the input data +/// \return returns the rolling statistics +/// \param timeData times of the input data (assumed to be sorted) +/// \param data values of the input data +/// \param times times for which to calculate the rolling statistics +/// \param deltaMax time range for which the rolling statistics is calculated +/// \param mNthreads number of threads to use for the calculation +/// \param minPoints minimum number of points to use for the calculation of the statistics - otherwise use nearest nClosestPoints points weighted with distance +/// \param nClosestPoints number of closest points in case of number of points in given range is smaller than minPoints +template +RollingStats getRollingStatistics(const DataTimeType& timeData, const DataType& data, const DataTime& times, const double deltaMax, const int mNthreads, const size_t minPoints = 4, const size_t nClosestPoints = 4) +{ + // output statistics + const size_t vecSize = times.size(); + RollingStats stats(vecSize); + + if (!std::is_sorted(timeData.begin(), timeData.end())) { + LOGP(error, "Input data is NOT sorted!"); + return stats; + } + + if (timeData.empty()) { + LOGP(error, "Input data is empty!"); + return stats; + } + + const size_t dataSize = data.size(); + const size_t timeDataSize = timeData.size(); + if (timeDataSize != dataSize) { + LOGP(error, "Input data has different sizes {}!={}", timeDataSize, dataSize); + return stats; + } + + auto myThread = [&](int iThread) { + // data in given time window for median calculation + DataType window; + for (size_t i = iThread; i < vecSize; i += mNthreads) { + const double timeI = times[i]; + + // lower index + const double timeStampLower = timeI - deltaMax; + const auto lower = std::lower_bound(timeData.begin(), timeData.end(), timeStampLower); + size_t idxStart = std::distance(timeData.begin(), lower); + + // upper index + const double timeStampUpper = timeI + deltaMax; + const auto upper = std::lower_bound(timeData.begin(), timeData.end(), timeStampUpper); + size_t idxEnd = std::distance(timeData.begin(), upper); + + // closest data point + if (auto idxClosest = findClosestIndices(timeData, timeI)) { + auto [idxLeft, idxRight] = *idxClosest; + const auto closestL = std::abs(timeData[idxLeft] - timeI); + const auto closestR = std::abs(timeData[idxRight] - timeI); + stats.closestDistanceL[i] = closestL; + stats.closestDistanceR[i] = closestR; + + // if no points are in the range use the n closest points - n from the left and n from the right + const size_t reqSize = idxEnd - idxStart; + if (reqSize < minPoints) { + // calculate weighted average + idxStart = (idxRight > nClosestPoints) ? (idxRight - nClosestPoints) : 0; + idxEnd = std::min(data.size(), idxRight + nClosestPoints); + constexpr float epsilon = 1e-6f; + double weightedSum = 0.0; + double weightTotal = 0.0; + for (size_t j = idxStart; j < idxEnd; ++j) { + const double dist = std::abs(timeI - timeData[j]); + const double weight = 1.0 / (dist + epsilon); + weightedSum += weight * data[j]; + weightTotal += weight; + } + stats.median[i] = (weightTotal > 0.) ? (weightedSum / weightTotal) : 0.0f; + } else { + // calculate statistics + stats.nPoints[i] = reqSize; + + if (idxStart >= data.size()) { + stats.median[i] = data.back(); + continue; + } + + if (reqSize <= 1) { + stats.median[i] = data[idxStart]; + continue; + } + + // calculate median + window.clear(); + if (reqSize > window.capacity()) { + window.reserve(static_cast(reqSize * 1.5)); + } + window.insert(window.end(), data.begin() + idxStart, data.begin() + idxEnd); + const size_t middle = window.size() / 2; + std::nth_element(window.begin(), window.begin() + middle, window.end()); + stats.median[i] = (window.size() % 2 == 1) ? window[middle] : ((window[middle - 1] + window[middle]) / 2.0); + + // calculate the stdev + const float mean = std::accumulate(window.begin(), window.end(), 0.0f) / window.size(); + std::transform(window.begin(), window.end(), window.begin(), [mean](const float val) { return val - mean; }); + const float sqsum = std::inner_product(window.begin(), window.end(), window.begin(), 0.0f); + const float stdev = std::sqrt(sqsum / window.size()); + stats.std[i] = stdev; + } + } + } + }; + + std::vector threads(mNthreads); + for (int i = 0; i < mNthreads; i++) { + threads[i] = std::thread(myThread, i); + } + + for (auto& th : threads) { + th.join(); + } + return stats; +} + } // namespace math_utils } // namespace o2 #endif diff --git a/Common/MathUtils/src/MathUtilsLinkDef.h b/Common/MathUtils/src/MathUtilsLinkDef.h index 6067dd540110c..0b070e537afcd 100644 --- a/Common/MathUtils/src/MathUtilsLinkDef.h +++ b/Common/MathUtils/src/MathUtilsLinkDef.h @@ -46,4 +46,6 @@ #pragma link C++ class o2::math_utils::Legendre1DPolynominal + ; #pragma link C++ class o2::math_utils::Legendre2DPolynominal + ; +#pragma link C++ class o2::math_utils::RollingStats + ; + #endif diff --git a/Common/MathUtils/test/testCartesian.cxx b/Common/MathUtils/test/testCartesian.cxx index ec04c34670fc3..9f2b4c912007e 100644 --- a/Common/MathUtils/test/testCartesian.cxx +++ b/Common/MathUtils/test/testCartesian.cxx @@ -77,7 +77,7 @@ BOOST_AUTO_TEST_CASE(Cartesian_test) BOOST_AUTO_TEST_CASE(Point3D_messageable) { using ElementType = math_utils::Point3D; - static_assert(std::is_trivially_copyable::value == true); + static_assert(o2::framework::is_forced_trivially_copyable::value == true); std::vector pts(10); auto makeElement = [](int idx) { return ElementType{idx, idx + 10, idx + 20}; diff --git a/Common/SimConfig/include/SimConfig/G4Params.h b/Common/SimConfig/include/SimConfig/G4Params.h index fd36ae046d520..aa8aa05263c0a 100644 --- a/Common/SimConfig/include/SimConfig/G4Params.h +++ b/Common/SimConfig/include/SimConfig/G4Params.h @@ -33,6 +33,13 @@ enum class EG4Physics { kUSER = 8 /* allows to give own string combination */ }; +// enumerating possible geometry navigation modes +// (understanding that geometry description is always done with TGeo) +enum class EG4Nav { + kTGeo = 0, /* navigate with TGeo */ + kG4 = 1 /* navigate with G4 native geometry */ +}; + // parameters to influence the G4 engine struct G4Params : public o2::conf::ConfigurableParamHelper { EG4Physics physicsmode = EG4Physics::kFTFP_BERT_EMV_optical; // default physics mode with which to configure G4 @@ -40,6 +47,8 @@ struct G4Params : public o2::conf::ConfigurableParamHelper { std::string configMacroFile = ""; // a user provided g4Config.in file (otherwise standard one fill be taken) std::string userPhysicsList = ""; // possibility to directly give physics list as string + EG4Nav navmode = EG4Nav::kTGeo; // geometry navigation mode (default TGeo) + std::string const& getPhysicsConfigString() const; O2ParamDef(G4Params, "G4"); diff --git a/Common/SimConfig/include/SimConfig/SimParams.h b/Common/SimConfig/include/SimConfig/SimParams.h index cf3ee2b01cf2e..b5f975d1b0c6e 100644 --- a/Common/SimConfig/include/SimConfig/SimParams.h +++ b/Common/SimConfig/include/SimConfig/SimParams.h @@ -44,7 +44,11 @@ struct SimCutParams : public o2::conf::ConfigurableParamHelper { struct SimMaterialParams : public o2::conf::ConfigurableParamHelper { // Local density value takes precedence over global density value, i.e. local values overwrite the global value. float globalDensityFactor = 1.f; // global factor that scales all material densities for systematic studies - std::string localDensityFactor; // Expected format: "SimMaterialParams.localDensityFactor=:,:,..." + // String to set densities on module or material level. Expected format: + // "SimMaterialParams.localDensityFactor=:,:,..." + // Example: "SimMaterialParams.localDensityFactor=TPC/Air:1.2,ITS:5." will scale the density of the Air in TPC + // with 1.2 and to 5.0 for all materials in ITS". + std::string localDensityFactor; O2ParamDef(SimMaterialParams, "SimMaterialParams"); }; diff --git a/Common/SimConfig/src/SimConfig.cxx b/Common/SimConfig/src/SimConfig.cxx index 9407a3c556179..15879687872d5 100644 --- a/Common/SimConfig/src/SimConfig.cxx +++ b/Common/SimConfig/src/SimConfig.cxx @@ -98,7 +98,8 @@ void SimConfig::determineActiveModules(std::vector const& inputargs activeModules[i] != "TF3" && activeModules[i] != "RCH" && activeModules[i] != "MI3" && - activeModules[i] != "ECL") { + activeModules[i] != "ECL" && + activeModules[i] != "FD3") { LOGP(fatal, "List of active modules contains {}, which is not a module from the upgrades.", activeModules[i]); } } @@ -112,7 +113,8 @@ void SimConfig::determineActiveModules(std::vector const& inputargs activeModules[i] == "TF3" || activeModules[i] == "RCH" || activeModules[i] == "MI3" || - activeModules[i] == "ECL") { + activeModules[i] == "ECL" || + activeModules[i] == "FD3") { LOGP(fatal, "List of active modules contains {}, which is not a run 3 module", activeModules[i]); } } @@ -130,6 +132,7 @@ void SimConfig::determineActiveModules(std::vector const& inputargs d == DetID::TF3 || d == DetID::RCH || d == DetID::ECL || + d == DetID::FD3 || d == DetID::MI3) { activeModules.emplace_back(DetID::getName(d)); } @@ -149,7 +152,7 @@ void SimConfig::determineActiveModules(std::vector const& inputargs activeModules.emplace_back("SHIL"); for (int d = DetID::First; d <= DetID::Last; ++d) { #ifdef ENABLE_UPGRADES - if (d != DetID::IT3 && d != DetID::TRK && d != DetID::FT3 && d != DetID::FCT && d != DetID::TF3 && d != DetID::RCH && d != DetID::ECL && d != DetID::MI3) { + if (d != DetID::IT3 && d != DetID::TRK && d != DetID::FT3 && d != DetID::FCT && d != DetID::TF3 && d != DetID::RCH && d != DetID::ECL && d != DetID::FD3 && d != DetID::MI3) { activeModules.emplace_back(DetID::getName(d)); } } @@ -197,7 +200,11 @@ bool SimConfig::determineActiveModulesList(const std::string& version, std::vect return false; } modules = map[version]; - LOGP(info, "Running with official detector version '{}'", version); + static std::string last_version{}; // prevent multiple printouts of same message + if (last_version != version) { + LOGP(info, "Running with official detector version '{}'", version); + last_version = version; + } } // check if specified modules are in list if (inputargs.size() != 1 || inputargs[0] != "all") { diff --git a/Common/SimConfig/src/SimConfigLinkDef.h b/Common/SimConfig/src/SimConfigLinkDef.h index 9c27536be5eb8..a1315e24ffedd 100644 --- a/Common/SimConfig/src/SimConfigLinkDef.h +++ b/Common/SimConfig/src/SimConfigLinkDef.h @@ -29,6 +29,7 @@ #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::conf::DigiParams> + ; #pragma link C++ enum o2::conf::EG4Physics; +#pragma link C++ enum o2::conf::EG4Nav; #pragma link C++ enum o2::conf::SimFieldMode; #pragma link C++ struct o2::conf::G4Params + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::conf::G4Params> + ; diff --git a/Common/Utils/CMakeLists.txt b/Common/Utils/CMakeLists.txt index 18f2aa7c1b6ed..849a3d70f62e1 100644 --- a/Common/Utils/CMakeLists.txt +++ b/Common/Utils/CMakeLists.txt @@ -26,7 +26,7 @@ o2_add_library(CommonUtils src/DebugStreamer.cxx src/DLLoaderBase.cxx PUBLIC_LINK_LIBRARIES ROOT::Hist ROOT::Tree Boost::iostreams O2::CommonDataFormat O2::Headers - FairLogger::FairLogger O2::MathUtils TBB::tbb) + FairLogger::FairLogger O2::MathUtils TBB::tbb O2::GPUCommon) o2_target_root_dictionary(CommonUtils HEADERS include/CommonUtils/TreeStream.h @@ -51,6 +51,15 @@ o2_target_root_dictionary(CommonUtils include/CommonUtils/IRFrameSelector.h include/CommonUtils/DebugStreamer.h) +# Extra dictionaries only needed if tests are built +if(BUILD_TESTING) + o2_add_library(CommonUtilsTest + SOURCES src/ConfigurableParamTest.cxx + PUBLIC_LINK_LIBRARIES O2::CommonUtils) + o2_target_root_dictionary(CommonUtilsTest + HEADERS include/CommonUtils/ConfigurableParamTest.h) +endif() + o2_add_test(TreeStream COMPONENT_NAME CommonUtils LABELS utils @@ -87,7 +96,16 @@ o2_add_test(EnumFlags SOURCES test/testEnumFlags.cxx PUBLIC_LINK_LIBRARIES O2::CommonUtils) +o2_add_test(ConfigurableParam + COMPONENT_NAME CommonUtils + LABELS utils + SOURCES test/testConfigurableParam.cxx + PUBLIC_LINK_LIBRARIES O2::CommonUtilsTest) + o2_add_executable(treemergertool COMPONENT_NAME CommonUtils SOURCES src/TreeMergerTool.cxx PUBLIC_LINK_LIBRARIES O2::CommonUtils Boost::program_options ROOT::Core) + +add_library(fpu_support OBJECT src/fpu.cxx) +add_library(O2::fpu_support ALIAS fpu_support) diff --git a/Common/Utils/include/CommonUtils/ConfigurableParam.h b/Common/Utils/include/CommonUtils/ConfigurableParam.h index 39b24bbbbd57c..b9234926b7c40 100644 --- a/Common/Utils/include/CommonUtils/ConfigurableParam.h +++ b/Common/Utils/include/CommonUtils/ConfigurableParam.h @@ -187,6 +187,9 @@ class ConfigurableParam // writes a human readable INI file of all parameters static void writeINI(std::string const& filename, std::string const& keyOnly = ""); + // writes a human readable INI or JSON file depending on the extension + static void write(std::string const& filename, std::string const& keyOnly = ""); + // can be used instead of using API on concrete child classes template static T getValueAs(std::string key) diff --git a/Common/Utils/include/CommonUtils/ConfigurableParamTest.h b/Common/Utils/include/CommonUtils/ConfigurableParamTest.h new file mode 100644 index 0000000000000..547bbf9ba8c38 --- /dev/null +++ b/Common/Utils/include/CommonUtils/ConfigurableParamTest.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 COMMON_CONFIGURABLE_PARAM_TEST_H_ +#define COMMON_CONFIGURABLE_PARAM_TEST_H_ + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +namespace o2::conf::test +{ +struct TestParam : public o2::conf::ConfigurableParamHelper { + enum TestEnum : uint8_t { + A, + B, + C + }; + + int iValue{42}; + float fValue{3.14}; + double dValue{3.14}; + bool bValue{true}; + unsigned uValue{1}; + long lValue{1}; + unsigned long ulValue{1}; + long long llValue{1}; + unsigned long long ullValue{1}; + std::string sValue = "default"; + int iValueProvenanceTest{0}; + TestEnum eValue = TestEnum::C; + int caValue[3] = {0, 1, 2}; + + O2ParamDef(TestParam, "TestParam"); +}; +} // namespace o2::conf::test + +#endif diff --git a/Common/Utils/include/CommonUtils/EnumFlags.h b/Common/Utils/include/CommonUtils/EnumFlags.h index fcd7d2d9e5e26..5032b6c0f1483 100644 --- a/Common/Utils/include/CommonUtils/EnumFlags.h +++ b/Common/Utils/include/CommonUtils/EnumFlags.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +35,9 @@ #include #include +#ifndef GPUCA_GPUCODE #include "CommonUtils/StringUtils.h" +#endif namespace o2::utils { @@ -54,9 +57,13 @@ concept EnumFlagHelper = requires { // functions and also check via concepts expected properties of the enum. // This is very much inspired by much more extensive libraries like magic_enum. // Inspiration by its c++20 version (https://github.com/fix8mt/conjure_enum). +// NOTE: Cannot detect if bit values past the underlying type are defined. +#ifndef GPUCA_GPUCODE template struct FlagsHelper final { using U = std::underlying_type_t; + using UMax = uint64_t; // max represetable type + static_assert(std::numeric_limits::digits <= std::numeric_limits::digits, "Underlying type has more digits than max supported digits"); static constexpr bool isScoped() noexcept { @@ -107,7 +114,7 @@ struct FlagsHelper final { static constexpr size_t MaxUnderScan{std::numeric_limits::digits}; // Maximum digits the underlying type has static constexpr size_t MaxScan{MaxUnderScan + MarginScan}; - // Checks if a given 'localation' contains an enum. + // Checks if a given 'location' contains an enum. template static constexpr bool isValid() noexcept { @@ -127,14 +134,14 @@ struct FlagsHelper final { // check if this is an anonymous enum return true; } - return false; -#else +#elif __GNUC__ else if constexpr (tpeek_v[tp + getSpec().size()] != '(' && tpeek_v.find_first_of(getSpec(), tp + getSpec().size()) != std::string_view::npos) { return true; - } else { - return false; } +#else +#error Unsupported compiler #endif + return false; } // Extract which values are present in the enum by checking all values in @@ -144,8 +151,8 @@ struct FlagsHelper final { { constexpr std::array valid{isValid(MinScan + I)>()...}; constexpr auto count{std::count_if(valid.cbegin(), valid.cend(), [](bool v) noexcept { return v; })}; - static_assert(count > 0, "Requiring non-empty enum!"); - static_assert(count <= MaxUnderScan, "Underlying type of enum has less digits than given expected!"); + static_assert(count > 0, "EnumFlag requires at least one enum value. Check that your enum has consecutive values starting from 0."); + static_assert(count <= MaxUnderScan, "Too many enum values for underlying type. Consider using a larger underlying type or fewer enum values."); std::array values{}; for (size_t idx{}, n{}; n < count; ++idx) { if (valid[idx]) { @@ -160,8 +167,17 @@ struct FlagsHelper final { static constexpr auto Max_v{Values.back()}; // Enum last entry static constexpr auto Min_u_v{static_cast(Min_v)}; // Enum first entry as size_t static constexpr auto Max_u_v{static_cast(Max_v)}; // Enum last entry as size_t - static constexpr bool isContinuous() noexcept { return (Max_u_v - Min_u_v + 1) == count(); } // Is the enum continuous - static constexpr auto MaxRep{((1 << (Max_u_v - Min_u_v + 1)) - 1) << Min_u_v}; // largest representable value + static_assert(Max_u_v < std::numeric_limits::digits, "Max Bit is beyond allow range deferred from underlying type"); + static constexpr bool isContinuous() noexcept { return (Max_u_v - Min_u_v + 1) == count(); } // Is the enum continuous + static constexpr UMax makeMaxRep(size_t min, size_t max) + { + const size_t width = max - min + 1; + if (width >= std::numeric_limits::digits) { + return std::numeric_limits::max(); + } + return ((UMax(1) << width) - 1) << min; + } + static constexpr auto MaxRep{makeMaxRep(Min_u_v, Max_u_v)}; // largest representable value template static constexpr std::string_view getName() @@ -172,7 +188,7 @@ struct FlagsHelper final { } if constexpr (tpeek_v[tp + getSpec().size()] == getSpec()) { #if defined __clang__ - if constexpr (tpeek_v[tp + getSpec().size() + 1] == getSpec()) { + if constexpr (tpeek_v[tp + getSpec().size() + 1] == getSpec()) { return {}; } #endif @@ -214,7 +230,7 @@ struct FlagsHelper final { template static constexpr auto getNameValue{getName()}; - template + template static constexpr auto getNames(std::index_sequence /*unused*/) { if constexpr (with_scope) { @@ -247,8 +263,8 @@ struct FlagsHelper final { static constexpr std::optional fromString(std::string_view str) noexcept { - for (std::size_t i{0}; i < count(); ++i) { - if (Names[i] == str || NamesScoped[i] == str) { + for (size_t i{0}; i < count(); ++i) { + if (isIEqual(Names[i], str) || isIEqual(NamesScoped[i], str)) { return Values[i]; } } @@ -267,7 +283,7 @@ struct FlagsHelper final { return toLower(a) == toLower(b); } - // Case-insensitive comparision for string_view. + // Case-insensitive comparison for string_view. static constexpr bool isIEqual(std::string_view s1, std::string_view s2) noexcept { if (s1.size() != s2.size()) { @@ -284,7 +300,7 @@ struct FlagsHelper final { static constexpr std::string_view None{"none"}; static constexpr bool hasNone() noexcept { - // check that enum does not contain memeber named 'none' + // check that enum does not contain member named 'none' for (size_t i{0}; i < count(); ++i) { if (isIEqual(Names[i], None)) { return true; @@ -296,7 +312,7 @@ struct FlagsHelper final { static constexpr std::string_view All{"all"}; static constexpr bool hasAll() noexcept { - // check that enum does not contain memeber named 'all' + // check that enum does not contain member named 'all' for (size_t i{0}; i < count(); ++i) { if (isIEqual(Names[i], All)) { return true; @@ -305,10 +321,12 @@ struct FlagsHelper final { return false; } }; +#endif } // namespace details::enum_flags // Require an enum to fullfil what one would except from a bitset. +#ifndef GPUCA_GPUCODE template concept EnumFlag = requires { // range checks @@ -320,11 +338,15 @@ concept EnumFlag = requires { requires !details::enum_flags::FlagsHelper::hasNone(); // added automatically requires !details::enum_flags::FlagsHelper::hasAll(); // added automatically }; +#else +template +concept EnumFlag = details::enum_flags::EnumFlagHelper; +#endif /** - * \brief Classs to aggregate and manage enum-based on-off flags. + * \brief Class to aggregate and manage enum-based on-off flags. * - * This class manages flags as bits in the underlying type of an enum, allowing + * This class manages flags as bits in the underlying type of an enum (upto 64 bits), allowing * manipulation via enum member names. It supports operations akin to std::bitset * but is fully constexpr and is ideal for aggregating multiple on-off booleans, * e.g., enabling/disabling algorithm features. @@ -345,7 +367,10 @@ concept EnumFlag = requires { template class EnumFlags { + static constexpr int DefaultBase{2}; +#ifndef GPUCA_GPUCODE using H = details::enum_flags::FlagsHelper; +#endif using U = std::underlying_type_t; U mBits{0}; @@ -370,17 +395,26 @@ class EnumFlags constexpr EnumFlags(const EnumFlags&) = default; // Move constructor. constexpr EnumFlags(EnumFlags&&) = default; - // Constructor to initialize with the underlyiny type. + // Constructor to initialize with the underlying type. constexpr explicit EnumFlags(U u) : mBits(u) {} // Initialize with a list of flags. constexpr EnumFlags(std::initializer_list flags) noexcept { - std::for_each(flags.begin(), flags.end(), [this](const E f) noexcept { mBits |= to_bit(f); }); + for (const E f : flags) { + mBits |= to_bit(f); + } + } +#ifndef GPUCA_GPUCODE + // Init from a string. + // + explicit EnumFlags(const std::string& str, int base = DefaultBase) + { + set(str, base); } - // Destructor. - constexpr ~EnumFlags() = default; +#endif - static constexpr U None{0}; // Represents no flags set. + static constexpr U None{0}; // Represents no flags set. +#ifndef GPUCA_GPUCODE static constexpr U All{H::MaxRep}; // Represents all flags set. // Return list of all enum values @@ -398,14 +432,14 @@ class EnumFlags // Sets flags from a string representation. // This can be either from a number representation (binary or digits) or // a concatenation of the enums members name e.g., 'Enum1|Enum2|...' - void set(const std::string& s = "", int base = 2) + void set(const std::string& s, int base = DefaultBase) { - // on throw restore previous state and rethrow - const U prev = mBits; - reset(); if (s.empty()) { // no-op return; } + // on throw restore previous state and rethrow + const U prev = mBits; + reset(); try { setImpl(s, base); } catch (const std::exception& e) { @@ -413,8 +447,9 @@ class EnumFlags throw; } } +#endif // Returns the raw bitset value. - constexpr auto value() const noexcept + [[nodiscard]] constexpr auto value() const noexcept { return mBits; } @@ -426,32 +461,42 @@ class EnumFlags } // Resets a specific flag. - template - requires std::is_same_v + template T> constexpr void reset(T t) { mBits &= ~to_bit(t); } // Tests if a specific flag is set. - template - requires std::is_same_v + template T> [[nodiscard]] constexpr bool test(T t) const noexcept { return (mBits & to_bit(t)) != None; } + // Tests if all specified flags are set. + template ... Ts> + [[nodiscard]] constexpr bool test(Ts... flags) const noexcept + { + return ((test(flags) && ...)); + } + // Sets a specific flag. - template - requires std::is_same_v + template T> constexpr void set(T t) noexcept { mBits |= to_bit(t); } + // Sets multiple specific flags. + template ... Ts> + constexpr void set(Ts... flags) noexcept + { + (set(flags), ...); + } + // Toggles a specific flag. - template - requires std::is_same_v + template T> constexpr void toggle(T t) noexcept { mBits ^= to_bit(t); @@ -463,6 +508,13 @@ class EnumFlags return mBits != None; } + // Checks if all flags are set. +#ifndef GPUCA_GPUCODE + [[nodiscard]] constexpr bool all() const noexcept + { + return mBits == All; + } + // Returns the bitset as a binary string. [[nodiscard]] std::string string() const { @@ -502,29 +554,29 @@ class EnumFlags } return oss.str(); } +#endif // Checks if any flag is set (Boolean context). - constexpr explicit operator bool() const noexcept + [[nodiscard]] constexpr explicit operator bool() const noexcept { return any(); } // Check if given flag is set. - template - requires std::is_same_v - constexpr bool operator[](const T t) noexcept + template T> + [[nodiscard]] constexpr bool operator[](const T t) const noexcept { return test(t); } // Checks if two flag sets are equal. - constexpr bool operator==(const EnumFlags& o) const noexcept + [[nodiscard]] constexpr bool operator==(const EnumFlags& o) const noexcept { return mBits == o.mBits; } // Checks if two flag sets are not equal. - constexpr bool operator!=(const EnumFlags& o) const noexcept + [[nodiscard]] constexpr bool operator!=(const EnumFlags& o) const noexcept { return mBits != o.mBits; } @@ -536,8 +588,7 @@ class EnumFlags constexpr EnumFlags& operator=(EnumFlags&& o) = default; // Performs a bitwise OR with a flag. - template - requires std::is_same_v + template T> constexpr EnumFlags& operator|=(T t) noexcept { mBits |= to_bit(t); @@ -545,8 +596,7 @@ class EnumFlags } // Performs a bitwise AND with a flag. - template - requires std::is_same_v + template T> constexpr EnumFlags& operator&=(T t) noexcept { mBits &= to_bit(t); @@ -554,8 +604,7 @@ class EnumFlags } // Returns a flag set with a bitwise AND. - template - requires std::is_same_v + template T> constexpr EnumFlags operator&(T t) const noexcept { return EnumFlags(mBits & to_bit(t)); @@ -583,7 +632,13 @@ class EnumFlags // Performs a bitwise XOR with another flag set. constexpr EnumFlags operator^(const EnumFlags& o) const noexcept { - return Flags(mBits ^ o.mBits); + return EnumFlags(mBits ^ o.mBits); + } + + // Performs a bitwise and with another flag set. + constexpr EnumFlags operator&(const EnumFlags& o) const noexcept + { + return EnumFlags(mBits & o.mBits); } // Performs a bitwise XOR assignment. @@ -595,19 +650,20 @@ class EnumFlags // Checks if all specified flags are set. template - constexpr bool all_of(Ts... flags) const noexcept + [[nodiscard]] constexpr bool all_of(Ts... flags) const noexcept { - return ((test(flags) && ...)); + return test(flags...); } // Checks if none of the specified flags are set. template - constexpr bool none_of(Ts... flags) const noexcept + [[nodiscard]] constexpr bool none_of(Ts... flags) const noexcept { return (!(test(flags) || ...)); } // Serializes the flag set to a string. +#ifndef GPUCA_GPUCODE [[nodiscard]] std::string serialize() const { return std::to_string(mBits); @@ -616,68 +672,126 @@ class EnumFlags // Deserializes a string into the flag set. void deserialize(const std::string& data) { - uint64_t v = std::stoul(data); + typename H::UMax v = std::stoul(data); if (v > H::MaxRep) { throw std::out_of_range("Values exceeds enum range."); } mBits = static_cast(v); } +#endif // Counts the number of set bits (active flags). [[nodiscard]] constexpr size_t count() const noexcept { - size_t c{0}; - for (size_t i{H::Min_u_v}; i < H::Max_u_v; ++i) { - if ((mBits & (U(1) << i)) != U(0)) { - ++c; - } - } - return c; + return std::popcount(mBits); } // Returns the union of two flag sets. - constexpr EnumFlags union_with(const EnumFlags& o) const noexcept + [[nodiscard]] constexpr EnumFlags union_with(const EnumFlags& o) const noexcept { return EnumFlags(mBits | o.mBits); } // Returns the intersection of two flag sets. - constexpr EnumFlags intersection_with(const EnumFlags& o) const noexcept + [[nodiscard]] constexpr EnumFlags intersection_with(const EnumFlags& o) const noexcept { return EnumFlags(mBits & o.mBits); } // Checks if all flags in another Flags object are present in the current object. - constexpr bool contains(const EnumFlags& other) const noexcept + [[nodiscard]] constexpr bool contains(const EnumFlags& other) const noexcept { return (mBits & other.mBits) == other.mBits; } private: - // Set implemnetation, bits was zeroed before. + // Set implementation, bits was zeroed before. +#ifndef GPUCA_GPUCODE void setImpl(const std::string& s, int base = 2) { + // Helper to check if character is valid for given base + auto isValidForBase = [](unsigned char c, int base) -> bool { + if (base == 2) { + return c == '0' || c == '1'; + } + if (base == 10) { + return std::isdigit(c); + } + if (base == 16) { + return std::isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); + } + return false; + }; + + // hex + if (base == 16) { + std::string_view hex_str{s}; + // Strip optional 0x or 0X prefix + if (s.size() >= 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { + hex_str.remove_prefix(2); + } + if (hex_str.empty()) { + throw std::invalid_argument("Empty hexadecimal string."); + } + if (!std::all_of(hex_str.begin(), hex_str.end(), [&](unsigned char c) { return isValidForBase(c, 16); })) { + throw std::invalid_argument("Invalid hexadecimal string."); + } + typename H::UMax v = std::stoul(std::string(hex_str), nullptr, 16); + if (v > H::MaxRep) { + throw std::out_of_range("Value exceeds enum range."); + } + mBits = static_cast(v); + return; + } + + // decimal and binary if (std::all_of(s.begin(), s.end(), [](unsigned char c) { return std::isdigit(c); })) { - if (base == 2) { // check of only 0 and 1 in string - if (!std::all_of(s.begin(), s.end(), [](char c) { return c == '0' || c == '1'; })) { + if (base == 2) { + // Binary: check only 0 and 1 + if (!std::all_of(s.begin(), s.end(), [&](unsigned char c) { return isValidForBase(c, 2); })) { throw std::invalid_argument("Invalid binary string."); } } - uint64_t v = std::stoul(s, nullptr, base); + typename H::UMax v = std::stoul(std::string(s), nullptr, base); if (v > H::MaxRep) { - throw std::out_of_range("Values exceeds enum range."); + throw std::out_of_range("Value exceeds enum range."); } mBits = static_cast(v); - } else if (std::all_of(s.begin(), s.end(), [](unsigned char c) { return std::isalnum(c) != 0 || c == '|' || c == ' ' || c == ':' || c == ','; })) { + } + // enum name strings + else if (std::all_of(s.begin(), s.end(), [](unsigned char c) { return std::isalnum(c) != 0 || c == '|' || c == ' ' || c == ':' || c == ',' || c == ';'; })) { std::string cs{s}; std::transform(cs.begin(), cs.end(), cs.begin(), [](unsigned char c) { return std::tolower(c); }); + if (cs == H::All) { mBits = All; } else if (cs == H::None) { mBits = None; } else { - char token = (s.find(',') != std::string::npos) ? ',' : '|'; - for (const auto& tok : Str::tokenize(s, token)) { + // Detect delimiter and ensure only one type is used + char token = ' '; + size_t pipePos = s.find('|'); + size_t commaPos = s.find(','); + size_t semiPos = s.find(';'); + + // Count how many different delimiters exist + int delimiterCount = (pipePos != std::string_view::npos ? 1 : 0) + + (commaPos != std::string_view::npos ? 1 : 0) + + (semiPos != std::string_view::npos ? 1 : 0); + + if (delimiterCount > 1) { + throw std::invalid_argument("Mixed delimiters not allowed!"); + } + + if (pipePos != std::string_view::npos) { + token = '|'; + } else if (commaPos != std::string_view::npos) { + token = ','; + } else if (semiPos != std::string_view::npos) { + token = ';'; + } + + for (const auto& tok : Str::tokenize(std::string(s), token)) { if (auto e = H::fromString(tok)) { mBits |= to_bit(*e); } else { @@ -689,14 +803,17 @@ class EnumFlags throw std::invalid_argument("Cannot parse string!"); } } +#endif }; +#ifndef GPUCA_GPUCODE template std::ostream& operator<<(std::ostream& os, const EnumFlags& f) { os << f.pstring(true); return os; } +#endif } // namespace o2::utils diff --git a/Common/Utils/include/CommonUtils/NameConf.h b/Common/Utils/include/CommonUtils/NameConf.h index 8a09a903bf32f..8d4c0a2c1c4f8 100644 --- a/Common/Utils/include/CommonUtils/NameConf.h +++ b/Common/Utils/include/CommonUtils/NameConf.h @@ -100,9 +100,15 @@ class NameConf : public o2::conf::ConfigurableParamHelper // CTF Dictionary static std::string getCTFDictFileName(); + // O2 Raw TF Filename + static std::string getRawTFFileName(uint32_t run, uint32_t orb, uint32_t id, const std::string& host, const std::string_view prefix = "o2_rawtf_dump"); + // Default CCDB server static std::string getCCDBServer(); + // create name to dump config file + static std::string getConfigOutputFileName(const std::string& procName, const std::string& confName = "", bool json = true); + protected: // 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, diff --git a/Common/Utils/include/CommonUtils/StringUtils.h b/Common/Utils/include/CommonUtils/StringUtils.h index c68e441d5b1c4..cfe29e065a78e 100644 --- a/Common/Utils/include/CommonUtils/StringUtils.h +++ b/Common/Utils/include/CommonUtils/StringUtils.h @@ -20,8 +20,7 @@ #include #include #include -#include -#include +#include "GPUCommonRtypes.h" namespace o2 { @@ -137,6 +136,9 @@ struct Str { // return vector of tokens from the string with provided delimiter. If requested, trim the spaces from tokens static std::vector tokenize(const std::string& src, char delim, bool trimToken = true, bool skipEmpty = true); + // return vector of tokens from the string with provided delimiters. If requested, trim the spaces from tokens + static std::vector tokenize(const std::string& src, const std::string& delim, bool trimToken = true, bool skipEmpty = true); + // concatenate arbitrary number of strings template static std::string concat_string(Ts const&... ts) diff --git a/Common/Utils/src/CommonUtilsTestLinkDef.h b/Common/Utils/src/CommonUtilsTestLinkDef.h new file mode 100644 index 0000000000000..9ee67f62fd7d0 --- /dev/null +++ b/Common/Utils/src/CommonUtilsTestLinkDef.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::conf::test::TestParam + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::conf::test::TestParam> + ; + +#endif diff --git a/Common/Utils/src/ConfigurableParam.cxx b/Common/Utils/src/ConfigurableParam.cxx index 8e242952bd61d..fd69f51402cd5 100644 --- a/Common/Utils/src/ConfigurableParam.cxx +++ b/Common/Utils/src/ConfigurableParam.cxx @@ -77,6 +77,30 @@ bool keyInTree(boost::property_tree::ptree* pt, const std::string& key) return reply; } +// Convert a type info to the appropiate literal suffix +std::string getLiteralSuffixFromType(const std::type_info& type) +{ + if (type == typeid(float)) { + return "f"; + } + if (type == typeid(long double)) { + return "l"; + } + if (type == typeid(unsigned int)) { + return "u"; + } + if (type == typeid(unsigned long)) { + return "ul"; + } + if (type == typeid(long long)) { + return "ll"; + } + if (type == typeid(unsigned long long)) { + return "ull"; + } + return ""; +} + // ------------------------------------------------------------------ void EnumRegistry::add(const std::string& key, const TDataMember* dm) @@ -168,6 +192,19 @@ int EnumLegalValues::getIntValue(const std::string& value) const // ----------------------------------------------------------------- +void ConfigurableParam::write(std::string const& filename, std::string const& keyOnly) +{ + if (o2::utils::Str::endsWith(filename, ".ini")) { + writeINI(filename, keyOnly); + } else if (o2::utils::Str::endsWith(filename, ".json")) { + writeJSON(filename, keyOnly); + } else { + throw std::invalid_argument(fmt::format("ConfigurabeParam output file name {} extension is neither .json nor .ini", filename)); + } +} + +// ----------------------------------------------------------------- + void ConfigurableParam::writeINI(std::string const& filename, std::string const& keyOnly) { if (sOutputDir == "/dev/null") { @@ -179,7 +216,10 @@ void ConfigurableParam::writeINI(std::string const& filename, std::string const& if (!keyOnly.empty()) { // write ini for selected key only try { boost::property_tree::ptree kTree; - kTree.add_child(keyOnly, sPtree->get_child(keyOnly)); + auto keys = o2::utils::Str::tokenize(keyOnly, " ,;", true, true); + for (const auto& k : keys) { + kTree.add_child(k, sPtree->get_child(k)); + } 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"; @@ -204,12 +244,42 @@ void ConfigurableParam::setValue(std::string const& key, std::string const& valu initialize(); } assert(sPtree); + auto setValueImpl = [&](std::string const& value) { + sPtree->put(key, value); + auto changed = updateThroughStorageMapWithConversion(key, value); + if (changed != EParamUpdateStatus::Failed) { + sValueProvenanceMap->find(key)->second = kRT; // set to runtime + } + }; try { if (sPtree->get_optional(key).is_initialized()) { - sPtree->put(key, valuestring); - auto changed = updateThroughStorageMapWithConversion(key, valuestring); - if (changed != EParamUpdateStatus::Failed) { - sValueProvenanceMap->find(key)->second = kRT; // set to runtime + try { + // try first setting value without stripping a literal suffix + setValueImpl(valuestring); + } catch (...) { + // try second stripping the expected literal suffix value for fundamental types + auto iter = sKeyToStorageMap->find(key); + if (iter == sKeyToStorageMap->end()) { + std::cerr << "Error in setValue (string) key is not known\n"; + return; + } + const auto expectedSuffix = getLiteralSuffixFromType(iter->second.first); + if (!expectedSuffix.empty()) { + auto valuestringLower = valuestring; + std::transform(valuestring.cbegin(), valuestring.cend(), valuestringLower.begin(), tolower); + if (valuestringLower.ends_with(expectedSuffix)) { + std::string strippedValue = valuestringLower.substr(0, valuestringLower.length() - expectedSuffix.length()); + setValueImpl(strippedValue); + } else { + // check if it has a different suffix and throw + for (const auto& suffix : {"f", "l", "u", "ul", "ll", "ull"}) { + if (valuestringLower.ends_with(suffix) && suffix != expectedSuffix) { + throw std::invalid_argument("Wrong type suffix: expected " + expectedSuffix + " but got " + suffix); + } + } + throw; // just rethrow the original exception + } + } } } } catch (std::exception const& e) { @@ -230,7 +300,10 @@ void ConfigurableParam::writeJSON(std::string const& filename, std::string const if (!keyOnly.empty()) { // write ini for selected key only try { boost::property_tree::ptree kTree; - kTree.add_child(keyOnly, sPtree->get_child(keyOnly)); + auto keys = o2::utils::Str::tokenize(keyOnly, " ,;", true, true); + for (const auto& k : keys) { + kTree.add_child(k, sPtree->get_child(k)); + } 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"; diff --git a/DataFormats/Detectors/MUON/MCH/src/DsChannelGroup.cxx b/Common/Utils/src/ConfigurableParamTest.cxx similarity index 85% rename from DataFormats/Detectors/MUON/MCH/src/DsChannelGroup.cxx rename to Common/Utils/src/ConfigurableParamTest.cxx index bcf10d74c95ff..5115a8dfe889d 100644 --- a/DataFormats/Detectors/MUON/MCH/src/DsChannelGroup.cxx +++ b/Common/Utils/src/ConfigurableParamTest.cxx @@ -9,8 +9,5 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "DataFormatsMCH/DsChannelGroup.h" - -std::string o2::mch::DsChannelId() const -{ -} +#include "CommonUtils/ConfigurableParamTest.h" +O2ParamImpl(o2::conf::test::TestParam); diff --git a/Common/Utils/src/DebugStreamer.cxx b/Common/Utils/src/DebugStreamer.cxx index 46ff9be83d415..3a5401ca9b382 100644 --- a/Common/Utils/src/DebugStreamer.cxx +++ b/Common/Utils/src/DebugStreamer.cxx @@ -10,18 +10,16 @@ // or submit itself to any jurisdiction. #include "CommonUtils/DebugStreamer.h" -#if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE) #include #include #include "TROOT.h" #include "TKey.h" #include #include "Framework/Logger.h" -#endif O2ParamImpl(o2::utils::ParameterDebugStreamer); -#if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE) && defined(DEBUG_STREAMER) +#if defined(DEBUG_STREAMER) o2::utils::DebugStreamer::DebugStreamer() { diff --git a/Common/Utils/src/NameConf.cxx b/Common/Utils/src/NameConf.cxx index 5a5f644f2da39..48cefacaf14c7 100644 --- a/Common/Utils/src/NameConf.cxx +++ b/Common/Utils/src/NameConf.cxx @@ -95,6 +95,11 @@ std::string NameConf::getCTFFileName(uint32_t run, uint32_t orb, uint32_t id, co return o2::utils::Str::concat_string(prefix, '_', fmt::format("run{:08d}_orbit{:010d}_tf{:010d}_{}", run, orb, id, host), ".root"); } +std::string NameConf::getRawTFFileName(uint32_t run, uint32_t orb, uint32_t id, const std::string& host, const std::string_view prefix) +{ + return o2::utils::Str::concat_string(prefix, '_', fmt::format("run{:08d}_orbit{:010d}_tf{:010d}_{}", run, orb, id, host), ".tf"); +} + std::string NameConf::getCTFDictFileName() { return o2::utils::Str::concat_string(CTFDICT, ".root"); @@ -111,3 +116,12 @@ std::string NameConf::getCCDBServer() { return Instance().mCCDBServer; } + +std::string NameConf::getConfigOutputFileName(const std::string& procName, const std::string& confName, bool json) +{ + std::string nm = procName; + if (!confName.empty()) { + nm += '_' + confName; + } + return fmt::format("ConfigParam_{}.{}", nm, json ? "json" : "ini"); +} diff --git a/Common/Utils/src/StringUtils.cxx b/Common/Utils/src/StringUtils.cxx index 4c0dd30ae6211..89f834d9a8f2e 100644 --- a/Common/Utils/src/StringUtils.cxx +++ b/Common/Utils/src/StringUtils.cxx @@ -12,8 +12,12 @@ #include "CommonUtils/StringUtils.h" #include #include +#ifndef GPUCA_STANDALONE #include +#include +#endif #include +#include using namespace o2::utils; @@ -34,6 +38,35 @@ std::vector Str::tokenize(const std::string& src, char delim, bool return tokens; } +std::vector Str::tokenize(const std::string& src, const std::string& delim, bool trimToken, bool skipEmpty) +{ + std::string inptStr{src}; + char* input = inptStr.data(); + auto mystrtok = [&]() -> char* { + input += std::strspn(input, delim.c_str()); + if (*input == '\0') { + return nullptr; + } + char* const token = input; + input += std::strcspn(input, delim.c_str()); + if (*input != '\0') { + *input++ = '\0'; + } + return token; + }; + std::vector tokens; + while (*input != '\0') { + std::string token = mystrtok(); + if (trimToken) { + trim(token); + } + if (!token.empty() || !skipEmpty) { + tokens.push_back(std::move(token)); + } + } + return tokens; +} + // replace all occurencies of from by to, return count int Str::replaceAll(std::string& s, const std::string& from, const std::string& to) { @@ -77,6 +110,7 @@ std::string Str::getFullPath(const std::string_view p) return std::filesystem::canonical(std::string{p}).string(); } +#ifndef GPUCA_STANDALONE std::string Str::rectifyDirectory(const std::string_view p) { std::string dir(p); @@ -104,6 +138,7 @@ std::string Str::rectifyDirectory(const std::string_view p) } return dir; } +#endif // 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 diff --git a/Common/Utils/test/testConfigurableParam.cxx b/Common/Utils/test/testConfigurableParam.cxx new file mode 100644 index 0000000000000..3ef177aaca3fe --- /dev/null +++ b/Common/Utils/test/testConfigurableParam.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. + +#define BOOST_TEST_MODULE Test ConfigurableParams +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include +#include +#include + +#include "CommonUtils/ConfigurableParamTest.h" + +using namespace o2::conf; +using namespace o2::conf::test; + +BOOST_AUTO_TEST_CASE(ConfigurableParam_Basic) +{ + // Tests the default parameters and also getter helpers. + auto& param = TestParam::Instance(); + BOOST_CHECK_EQUAL(param.iValue, 42); + BOOST_CHECK_EQUAL(param.dValue, 3.14); + BOOST_CHECK_EQUAL(param.bValue, true); + BOOST_CHECK_EQUAL(param.sValue, "default"); + BOOST_CHECK_EQUAL(static_cast(param.eValue), 2); + + BOOST_CHECK_EQUAL(ConfigurableParam::getValueAs("TestParam.iValue"), 42); + BOOST_CHECK_EQUAL(ConfigurableParam::getValueAs("TestParam.dValue"), 3.14); + BOOST_CHECK_EQUAL(ConfigurableParam::getValueAs("TestParam.bValue"), true); + BOOST_CHECK_EQUAL(ConfigurableParam::getValueAs("TestParam.sValue"), "default"); +} + +BOOST_AUTO_TEST_CASE(ConfigurableParam_SG_Fundamental) +{ + // tests runtime setting and getting for fundamental types + ConfigurableParam::setValue("TestParam.iValue", "100"); + ConfigurableParam::setValue("TestParam.dValue", "2.718"); + ConfigurableParam::setValue("TestParam.bValue", "0"); + ConfigurableParam::setValue("TestParam.sValue", "modified"); + ConfigurableParam::setValue("TestParam.eValue", "0"); + + auto& param = TestParam::Instance(); + param.printKeyValues(); + BOOST_CHECK_EQUAL(param.iValue, 100); + BOOST_CHECK_EQUAL(param.dValue, 2.718); + BOOST_CHECK_EQUAL(param.bValue, false); + BOOST_CHECK_EQUAL(param.sValue, "modified"); + BOOST_CHECK_EQUAL(static_cast(param.eValue), 0); +} + +BOOST_AUTO_TEST_CASE(ConfigurableParam_SG_CArray) +{ + // tests setting and getting for a c-style array type + auto& param = TestParam::Instance(); + BOOST_CHECK_EQUAL(ConfigurableParam::getValueAs("TestParam.caValue[0]"), 0); + BOOST_CHECK_EQUAL(ConfigurableParam::getValueAs("TestParam.caValue[1]"), 1); + BOOST_CHECK_EQUAL(ConfigurableParam::getValueAs("TestParam.caValue[2]"), 2); + + ConfigurableParam::setValue("TestParam.caValue[1]", "99"); + BOOST_CHECK_EQUAL(ConfigurableParam::getValueAs("TestParam.caValue[1]"), 99); +} + +BOOST_AUTO_TEST_CASE(ConfigurableParam_Provenance) +{ + // tests correct setting of provenance + BOOST_CHECK_EQUAL(ConfigurableParam::getProvenance("TestParam.iValueProvenanceTest"), ConfigurableParam::EParamProvenance::kCODE); + ConfigurableParam::setValue("TestParam.iValueProvenanceTest", "123"); + BOOST_CHECK_EQUAL(ConfigurableParam::getProvenance("TestParam.iValueProvenanceTest"), ConfigurableParam::EParamProvenance::kRT); +} + +BOOST_AUTO_TEST_CASE(ConfigurableParam_FileIO_Ini) +{ + // test for ini file serialization + const std::string testFileName = "test_config.ini"; + auto iValueBefore = TestParam::Instance().iValue; + auto sValueBefore = TestParam::Instance().sValue; + ConfigurableParam::writeINI(testFileName); + ConfigurableParam::setValue("TestParam.iValue", "999"); + ConfigurableParam::setValue("TestParam.sValue", testFileName); + ConfigurableParam::updateFromFile(testFileName); + BOOST_CHECK_EQUAL(TestParam::Instance().iValue, iValueBefore); + BOOST_CHECK_EQUAL(TestParam::Instance().sValue, sValueBefore); + std::remove(testFileName.c_str()); +} + +BOOST_AUTO_TEST_CASE(ConfigurableParam_FileIO_Json) +{ + // test for json file serialization + const std::string testFileName = "test_config.json"; + auto iValueBefore = TestParam::Instance().iValue; + auto sValueBefore = TestParam::Instance().sValue; + ConfigurableParam::writeJSON(testFileName); + ConfigurableParam::setValue("TestParam.iValue", "999"); + ConfigurableParam::setValue("TestParam.sValue", testFileName); + ConfigurableParam::updateFromFile(testFileName); + BOOST_CHECK_EQUAL(TestParam::Instance().iValue, iValueBefore); + BOOST_CHECK_EQUAL(TestParam::Instance().sValue, sValueBefore); + std::remove(testFileName.c_str()); +} + +BOOST_AUTO_TEST_CASE(ConfigurableParam_FileIO_ROOT) +{ + // test for root file serialization + const std::string testFileName = "test_config.root"; + auto iValueBefore = TestParam::Instance().iValue; + auto sValueBefore = TestParam::Instance().sValue; + TFile* testFile = TFile::Open(testFileName.c_str(), "RECREATE"); + TestParam::Instance().serializeTo(testFile); + testFile->Close(); + ConfigurableParam::setValue("TestParam.iValue", "999"); + ConfigurableParam::setValue("TestParam.sValue", testFileName); + ConfigurableParam::fromCCDB(testFileName); + BOOST_CHECK_EQUAL(TestParam::Instance().iValue, iValueBefore); + BOOST_CHECK_EQUAL(TestParam::Instance().sValue, sValueBefore); + std::remove(testFileName.c_str()); +} + +BOOST_AUTO_TEST_CASE(ConfigurableParam_Cli) +{ + // test setting values from as a cli arg string + ConfigurableParam::updateFromString("TestParam.iValue=55;TestParam.sValue=cli"); + BOOST_CHECK_EQUAL(TestParam::Instance().iValue, 55); + BOOST_CHECK_EQUAL(TestParam::Instance().sValue, "cli"); +} + +BOOST_AUTO_TEST_CASE(ConfigurableParam_LiteralSuffix) +{ + // test setting values with the correct literal suffix + ConfigurableParam::updateFromString("TestParam.fValue=42.f"); + BOOST_CHECK_EQUAL(TestParam::Instance().fValue, 42.f); + + ConfigurableParam::setValue("TestParam.ullValue", "999ull"); + BOOST_CHECK_EQUAL(TestParam::Instance().ullValue, 999ULL); + // check using wrong literal suffix fails, prints error to std + ConfigurableParam::setValue("TestParam.ullValue", "888u"); + BOOST_CHECK_NE(TestParam::Instance().ullValue, 888); +} diff --git a/Common/Utils/test/testEnumFlags.cxx b/Common/Utils/test/testEnumFlags.cxx index 5c8b71eb9040a..9101ffb97fdfe 100644 --- a/Common/Utils/test/testEnumFlags.cxx +++ b/Common/Utils/test/testEnumFlags.cxx @@ -14,6 +14,9 @@ #define BOOST_TEST_DYN_LINK #include +#include +#include + #include #include @@ -21,13 +24,25 @@ // Example enum to use with EnumFlags enum class TestEnum : uint8_t { - Bit1, + Bit1 = 0, Bit2, Bit3, Bit4, Bit5VeryLongName, }; +// Very long enum +// to test that it works beyond 32 bits upto 64 bits +#define ENUM_BIT_NAME(n) Bit##n +#define ENUM_BIT_NAME_EXPAND(n) ENUM_BIT_NAME(n) +#define ENUM_BIT(z, n, _) ENUM_BIT_NAME_EXPAND(BOOST_PP_INC(n)) = (n), +enum class TestEnumLong : uint64_t { + BOOST_PP_REPEAT(64, ENUM_BIT, _) +}; +#undef ENUM_BIT +#undef ENUM_BIT_NAME +#undef ENUM_BIT_NAME_EXPAND + BOOST_AUTO_TEST_CASE(Flags_test) { using EFlags = o2::utils::EnumFlags; @@ -59,11 +74,22 @@ BOOST_AUTO_TEST_CASE(Flags_test) multipleFlags.reset(); BOOST_TEST(!multipleFlags.any()); + // Test multiset + multipleFlags.reset(); + multipleFlags.set(TestEnum::Bit2, TestEnum::Bit4); + BOOST_TEST(!multipleFlags.test(TestEnum::Bit1)); + BOOST_TEST(multipleFlags.test(TestEnum::Bit2)); + BOOST_TEST(!multipleFlags.test(TestEnum::Bit3)); + BOOST_TEST(multipleFlags.test(TestEnum::Bit4)); + BOOST_TEST(!multipleFlags.test(TestEnum::Bit5VeryLongName)); + // Test operator| EFlags combinedFlags = flag1 | EFlags(TestEnum::Bit2); BOOST_TEST(combinedFlags.test(TestEnum::Bit1)); BOOST_TEST(combinedFlags.test(TestEnum::Bit2)); BOOST_TEST(!combinedFlags.test(TestEnum::Bit3)); + combinedFlags |= TestEnum::Bit5VeryLongName; + BOOST_TEST(combinedFlags.test(TestEnum::Bit5VeryLongName)); // Test operator[] BOOST_TEST(combinedFlags[TestEnum::Bit1]); @@ -141,7 +167,7 @@ BOOST_AUTO_TEST_CASE(Flags_test) BOOST_TEST(flags.test(TestEnum::Bit4)); } - { // test with different delimiter + { // test with , delimiter std::string str = "Bit4,TestEnum::Bit2 , Bit1 "; flags.set(str); BOOST_TEST(flags.test(TestEnum::Bit1)); @@ -150,6 +176,15 @@ BOOST_AUTO_TEST_CASE(Flags_test) BOOST_TEST(flags.test(TestEnum::Bit4)); } + { // test with ; delimiter + std::string str = "Bit4;TestEnum::Bit2 ; Bit1 "; + flags.set(str); + BOOST_TEST(flags.test(TestEnum::Bit1)); + BOOST_TEST(flags.test(TestEnum::Bit2)); + BOOST_TEST(!flags.test(TestEnum::Bit3)); + BOOST_TEST(flags.test(TestEnum::Bit4)); + } + { // throw test with mixed delimiter std::string str = "Bit4|TestEnum::Bit2 , Bit1 "; BOOST_CHECK_THROW(flags.set(str), std::invalid_argument); @@ -235,6 +270,14 @@ BOOST_AUTO_TEST_CASE(Flags_test) EFlags flags3{TestEnum::Bit1, TestEnum::Bit2, TestEnum::Bit3}; EFlags flags4{TestEnum::Bit2, TestEnum::Bit3, TestEnum::Bit4}; + // test xor + auto flagsXOR = flags3 ^ flags4; + BOOST_CHECK(flagsXOR.test(TestEnum::Bit1, TestEnum::Bit4)); + + // test and + auto flagsAND = flags3 & flags4; + BOOST_CHECK(flagsAND.test(TestEnum::Bit2, TestEnum::Bit3)); + // Perform an intersection operation EFlags intersectionFlags = flags3.intersection_with(flags4); BOOST_CHECK(intersectionFlags.test(TestEnum::Bit2)); @@ -244,6 +287,14 @@ BOOST_AUTO_TEST_CASE(Flags_test) BOOST_CHECK_EQUAL(intersectionFlags.value(), 6); // 0110 in binary } + { + // Check special flag names. + EFlags flag("all"); + BOOST_CHECK(flag.all()); + flag.set("none"); + BOOST_CHECK(!flag.any()); + } + { // Create two flag sets EFlags flags1{TestEnum::Bit1, TestEnum::Bit2, TestEnum::Bit3}; @@ -257,4 +308,346 @@ BOOST_AUTO_TEST_CASE(Flags_test) EFlags flags3{TestEnum::Bit4}; BOOST_CHECK(!flags1.contains(flags3)); // flags1 does not contain flags3 } + + { + // Test compilation using an enum with more than 32 bits + // Also tests space delimiter and construction from string. + o2::utils::EnumFlags test("Bit32 Bit34"); + BOOST_CHECK(test.test(TestEnumLong::Bit32, TestEnumLong::Bit34)); + BOOST_CHECK(!test.test(TestEnumLong::Bit1, TestEnumLong::Bit23)); + } +} + +BOOST_AUTO_TEST_CASE(Flags_case_insensitive_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test case-insensitive flag names + { + EFlags flags("bit1"); // lowercase + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(!flags.test(TestEnum::Bit2)); + } + + { + EFlags flags("BIT2"); // uppercase + BOOST_CHECK(flags.test(TestEnum::Bit2)); + BOOST_CHECK(!flags.test(TestEnum::Bit1)); + } + + { + EFlags flags("BiT3"); // mixed case + BOOST_CHECK(flags.test(TestEnum::Bit3)); + } + + { + EFlags flags("bit1|BIT2|BiT3"); // mixed case with delimiter + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + BOOST_CHECK(flags.test(TestEnum::Bit3)); + } + + // Test special keywords case-insensitive + { + EFlags flags("ALL"); + BOOST_CHECK(flags.all()); + } + + { + EFlags flags("None"); + BOOST_CHECK(!flags.any()); + } +} + +BOOST_AUTO_TEST_CASE(Flags_error_recovery_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test that previous state is restored on exception + { + EFlags flags({TestEnum::Bit1, TestEnum::Bit2}); + auto previousValue = flags.value(); + + // Try to set with invalid string + BOOST_CHECK_THROW(flags.set("InvalidFlag"), std::invalid_argument); + + // Verify state was restored + BOOST_CHECK_EQUAL(flags.value(), previousValue); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + } + + { + EFlags flags({TestEnum::Bit3, TestEnum::Bit4}); + auto previousValue = flags.value(); + + // Try to set with out-of-range value + BOOST_CHECK_THROW(flags.set("999999", 10), std::out_of_range); + + // Verify state was restored + BOOST_CHECK_EQUAL(flags.value(), previousValue); + BOOST_CHECK(flags.test(TestEnum::Bit3)); + BOOST_CHECK(flags.test(TestEnum::Bit4)); + } + + { + EFlags flags(TestEnum::Bit5VeryLongName); + auto previousValue = flags.value(); + + // Try to set with invalid binary string + BOOST_CHECK_THROW(flags.set("10102", 2), std::invalid_argument); + + // Verify state was restored + BOOST_CHECK_EQUAL(flags.value(), previousValue); + BOOST_CHECK(flags.test(TestEnum::Bit5VeryLongName)); + } +} + +BOOST_AUTO_TEST_CASE(Flags_whitespace_handling_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test leading/trailing whitespace + { + EFlags flags(" Bit1 "); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + } + + { + EFlags flags(" Bit1 | Bit2 "); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + } + + // Test excessive whitespace between flags + { + EFlags flags("Bit1 | Bit3"); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit3)); + BOOST_CHECK(!flags.test(TestEnum::Bit2)); + } + + // Test tabs and other whitespace (should work with space delimiter) + { + EFlags flags("Bit1 Bit2 Bit3"); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + BOOST_CHECK(flags.test(TestEnum::Bit3)); + } +} + +BOOST_AUTO_TEST_CASE(Flags_count_bits_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test counting set bits + { + EFlags flags; + BOOST_CHECK_EQUAL(flags.count(), 0); + } + + { + EFlags flags(TestEnum::Bit1); + BOOST_CHECK_EQUAL(flags.count(), 1); + } + + { + EFlags flags({TestEnum::Bit1, TestEnum::Bit2}); + BOOST_CHECK_EQUAL(flags.count(), 2); + } + + { + EFlags flags({TestEnum::Bit1, TestEnum::Bit2, TestEnum::Bit3, TestEnum::Bit4}); + BOOST_CHECK_EQUAL(flags.count(), 4); + } + + { + EFlags flags(EFlags::All); + BOOST_CHECK_EQUAL(flags.count(), 5); // TestEnum has 5 members + } + + // Test count after operations + { + EFlags flags({TestEnum::Bit1, TestEnum::Bit2, TestEnum::Bit3}); + BOOST_CHECK_EQUAL(flags.count(), 3); + + flags.reset(TestEnum::Bit2); + BOOST_CHECK_EQUAL(flags.count(), 2); + + flags.set(TestEnum::Bit4); + BOOST_CHECK_EQUAL(flags.count(), 3); + + flags.toggle(TestEnum::Bit1); + BOOST_CHECK_EQUAL(flags.count(), 2); + } +} + +BOOST_AUTO_TEST_CASE(Flags_mixed_delimiter_validation_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test that mixed delimiters throw an error + { + BOOST_CHECK_THROW(EFlags("Bit1|Bit2,Bit3"), std::invalid_argument); + } + + { + BOOST_CHECK_THROW(EFlags("Bit1;Bit2|Bit3"), std::invalid_argument); + } + + { + BOOST_CHECK_THROW(EFlags("Bit1,Bit2;Bit3"), std::invalid_argument); + } + + { + BOOST_CHECK_THROW(EFlags("Bit1|Bit2,Bit3;Bit4"), std::invalid_argument); + } + + // Test that single delimiter types work + { + EFlags flags1("Bit1|Bit2|Bit3"); + BOOST_CHECK_EQUAL(flags1.count(), 3); + } + + { + EFlags flags2("Bit1,Bit2,Bit3"); + BOOST_CHECK_EQUAL(flags2.count(), 3); + } + + { + EFlags flags3("Bit1;Bit2;Bit3"); + BOOST_CHECK_EQUAL(flags3.count(), 3); + } +} + +BOOST_AUTO_TEST_CASE(Flags_empty_and_edge_cases_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test empty string + { + EFlags flags({TestEnum::Bit1, TestEnum::Bit2}); + flags.set(""); // Should be no-op + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + } + + // Test with only whitespace + { + EFlags flags({TestEnum::Bit1}); + flags.set(" "); // Should result in empty after tokenization + // Depending on implementation, this might clear or throw + // Adjust expectation based on actual behavior + } + + // Test duplicate flags (should work, setting same bit twice is idempotent) + { + EFlags flags("Bit1|Bit1|Bit1"); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK_EQUAL(flags.count(), 1); + } + + // Test scoped and unscoped mixed + { + EFlags flags("Bit1|TestEnum::Bit2"); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + } +} + +BOOST_AUTO_TEST_CASE(Flags_binary_decimal_parsing_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test binary parsing + { + EFlags flags("101", 2); + BOOST_CHECK(flags.test(TestEnum::Bit1)); // bit 0 + BOOST_CHECK(!flags.test(TestEnum::Bit2)); // bit 1 + BOOST_CHECK(flags.test(TestEnum::Bit3)); // bit 2 + } + + // Test decimal parsing + { + EFlags flags("7", 10); // 7 = 0b111 + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + BOOST_CHECK(flags.test(TestEnum::Bit3)); + BOOST_CHECK(!flags.test(TestEnum::Bit4)); + } + + // Test hexadecimal parsing + { + EFlags flags("F", 16); // 15 = 0b1111 + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + BOOST_CHECK(flags.test(TestEnum::Bit3)); + BOOST_CHECK(flags.test(TestEnum::Bit4)); + BOOST_CHECK(!flags.test(TestEnum::Bit5VeryLongName)); + } + + // Test hexadecimal with 0x prefix + { + EFlags flags("0xA", 16); // 10 = 0b1010 + BOOST_CHECK(!flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + BOOST_CHECK(!flags.test(TestEnum::Bit3)); + BOOST_CHECK(flags.test(TestEnum::Bit4)); + } + + // Test hexadecimal with 0X prefix (uppercase) + { + EFlags flags("0X1F", 16); // 31 = all 5 bits + BOOST_CHECK(flags.all()); + } + + // Test lowercase hex digits + { + EFlags flags("0xa", 16); + BOOST_CHECK_EQUAL(flags.value(), 10); + } + + // Test thros + { + BOOST_CHECK_THROW(EFlags("0xAbCd", 16), std::out_of_range); + } + + // Test invalid binary string (contains 2) + { + BOOST_CHECK_THROW(EFlags("1012", 2), std::invalid_argument); + } + + // Test out of range for base + { + BOOST_CHECK_THROW(EFlags("100000", 2), std::out_of_range); + } +} + +BOOST_AUTO_TEST_CASE(Flags_operator_bool_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test explicit bool conversion + { + EFlags empty; + BOOST_CHECK(!static_cast(empty)); + } + + { + EFlags withFlag(TestEnum::Bit1); + BOOST_CHECK(static_cast(withFlag)); + } + + // Test in conditional + { + EFlags flags; + if (flags) { + BOOST_FAIL("Empty flags should be false"); + } + + flags.set(TestEnum::Bit1); + if (!flags) { + BOOST_FAIL("Non-empty flags should be true"); + } + } } diff --git a/DataFormats/Detectors/CTP/include/DataFormatsCTP/Configuration.h b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Configuration.h index fdd73986f1eaf..ff1462084d53d 100644 --- a/DataFormats/Detectors/CTP/include/DataFormatsCTP/Configuration.h +++ b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Configuration.h @@ -160,7 +160,7 @@ class CTPConfiguration const std::vector& getCTPClasses() const { return mCTPClasses; } // Read-only interface uint64_t getInputMask(const std::string& name) const; int getInputIndex(const std::string& name) const; - std::string getClassNameFromIndex(int index) { return mCTPClasses[index].name; }; + std::string getClassNameFromIndex(int index); std::string getClassNameFromHWIndex(int index); const CTPClass* getCTPClassFromHWIndex(const int index) const; bool isMaskInInputs(const uint64_t& mask) const; @@ -214,7 +214,8 @@ struct CtpCfg { uint32_t orbitShift = 0; uint32_t irInputs_1_24 = 0; uint32_t irInputs_25_48 = 0; - ClassDefNV(CtpCfg, 1) + std::vector listOfUsedInputs(); + ClassDefNV(CtpCfg, 2) }; } // namespace ctp } // namespace o2 diff --git a/DataFormats/Detectors/CTP/src/CTPRateFetcher.cxx b/DataFormats/Detectors/CTP/src/CTPRateFetcher.cxx index d899fcafec47d..5f31fe5741240 100644 --- a/DataFormats/Detectors/CTP/src/CTPRateFetcher.cxx +++ b/DataFormats/Detectors/CTP/src/CTPRateFetcher.cxx @@ -254,7 +254,7 @@ void CTPRateFetcher::setupRun(int runNumber, o2::ccdb::BasicCCDBManager* ccdb, u return; } mLHCIFdata = *ptrLHCIFdata; - std::map metadata; + std::map metadata; metadata["runNumber"] = std::to_string(mRunNumber); auto ptrConfig = ccdb->getSpecific("CTP/Config/Config", timeStamp, metadata); if (ptrConfig == nullptr) { diff --git a/DataFormats/Detectors/CTP/src/Configuration.cxx b/DataFormats/Detectors/CTP/src/Configuration.cxx index 38a49132db3d1..98458ef06d1d3 100644 --- a/DataFormats/Detectors/CTP/src/Configuration.cxx +++ b/DataFormats/Detectors/CTP/src/Configuration.cxx @@ -780,6 +780,15 @@ int CTPConfiguration::getInputIndex(const std::string& name) const LOG(info) << "input:" << name << " index:" << index; return index; } +std::string CTPConfiguration::getClassNameFromIndex(int index) +{ + if (index < (int)mCTPClasses.size()) { + return mCTPClasses[index].name; + } else { + std::string name = "Cls" + std::to_string(index); + return name; + } +}; std::string CTPConfiguration::getClassNameFromHWIndex(int index) { for (auto& cls : mCTPClasses) { @@ -924,8 +933,9 @@ uint64_t CTPConfiguration::getTriggerClassMaskWInputsNoTrgDets() const exclude += cls.name.find("EMC") != std::string::npos; exclude += cls.name.find("TRD") != std::string::npos; exclude += cls.name.find("HMP") != std::string::npos; - if (!exclude) + if (!exclude) { clsmask |= cls.classMask; + } } return clsmask; } @@ -1217,9 +1227,24 @@ int CtpCfg::readAndSave(std::string& path) } return 0; } - +std::vector CtpCfg::listOfUsedInputs() +{ + std::cout << std::hex << "0x" << irInputs_1_24 << " " << irInputs_25_48 << std::dec << std::endl; + std::vector inputList; + for (int i = 0; i < 24; i++) { + if ((1ul << i) & irInputs_1_24) { + inputList.push_back(i); + } + } + for (int i = 0; i < 24; i++) { + if ((1ul << i) & irInputs_25_48) { + inputList.push_back(i + 24); + } + } + return inputList; +} std::ostream& o2::ctp::operator<<(std::ostream& in, const o2::ctp::CTPConfiguration& conf) { conf.printStream(in); return in; -} +} \ No newline at end of file diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/AlignParam.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/AlignParam.h index c4e702c6ae27e..5a0d2d64b0ff5 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/AlignParam.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/AlignParam.h @@ -37,9 +37,12 @@ class AlignParam 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 = true); // global (preferable) or local delta definition + bool global = true, // global (preferable) or local delta definition + bool convertLocalToGlobal = true); // if local is provided, convert it to global - AlignParam(const char* symname, int algID, TGeoMatrix& m, bool global = true); + AlignParam(const char* symname, int algID, TGeoMatrix& m, + bool global = true, // global (preferable) or local delta definition + bool convertLocalToGlobal = true); // if local is provided, convert it to global /// return symbolic name of the volume const std::string& getSymName() const { return mSymName; } @@ -52,7 +55,7 @@ class AlignParam double getZ() const { return mZ; } /// apply object to geoemetry - bool applyToGeometry() const; + bool applyToGeometry(int printLevel = -1) const; /// extract global delta matrix TGeoHMatrix createMatrix() const; @@ -70,6 +73,9 @@ class AlignParam void setAlignableID(int id) { mAlignableID = id; } /// ================ methods for direct setting of delta params + /// set parameters + void setParams(double x, double y, double z, double psi, double theta, double phi); + /// set parameters of global delta void setGlobalParams(double x, double y, double z, double psi, double theta, double phi); @@ -114,6 +120,9 @@ class AlignParam int rectify(double zero = 1e-13); + bool isGlobal() const { return mIsGlobal; } + void setIsGlobal(bool v) { mIsGlobal = v; } + protected: bool matrixToAngles(const double* rot, double& psi, double& theta, double& phi) const; void anglesToMatrix(double psi, double theta, double phi, double* rot) const; @@ -123,8 +132,8 @@ class AlignParam private: std::string mSymName{}; + bool mIsGlobal = true; /// is this global delta? int mAlignableID = -1; /// alignable ID (set for sensors only) - double mX = 0.; ///< X translation of global delta double mY = 0.; ///< Y translation of global delta double mZ = 0.; ///< Z translation of global delta @@ -133,7 +142,7 @@ class AlignParam 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) - ClassDefNV(AlignParam, 1); + ClassDefNV(AlignParam, 2); }; } // namespace detectors diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/DetID.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/DetID.h index a2767c7620cdd..2d2383783cfc3 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/DetID.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/DetID.h @@ -87,7 +87,8 @@ class DetID static constexpr ID RCH = 23; static constexpr ID MI3 = 24; static constexpr ID ECL = 25; - static constexpr ID Last = ECL; + static constexpr ID FD3 = 26; + static constexpr ID Last = FD3; #else static constexpr ID Last = FOC; ///< if extra detectors added, update this !!! #endif @@ -181,7 +182,7 @@ class DetID // 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", "TST", "CTP", "FOC", "IT3", "TRK", "FT3", "FCT", "TF3", "RCH", "MI3", "ECL", nullptr}; + {"ITS", "TPC", "TRD", "TOF", "PHS", "CPV", "EMC", "HMP", "MFT", "MCH", "MID", "ZDC", "FT0", "FV0", "FDD", "TST", "CTP", "FOC", "IT3", "TRK", "FT3", "FCT", "TF3", "RCH", "MI3", "ECL", "FD3", nullptr}; #else {"ITS", "TPC", "TRD", "TOF", "PHS", "CPV", "EMC", "HMP", "MFT", "MCH", "MID", "ZDC", "FT0", "FV0", "FDD", "TST", "CTP", "FOC", nullptr}; #endif @@ -195,7 +196,7 @@ class DetID #ifdef ENABLE_UPGRADES , o2h::gDataOriginIT3, o2h::gDataOriginTRK, o2h::gDataOriginFT3, o2h::gDataOriginFCT, o2h::gDataOriginTF3, - o2h::gDataOriginRCH, o2h::gDataOriginMI3, o2h::gDataOriginECL + o2h::gDataOriginRCH, o2h::gDataOriginMI3, o2h::gDataOriginECL, o2h::gDataOriginFD3 #endif }; #endif // GPUCA_GPUCODE_DEVICE @@ -211,10 +212,11 @@ GPUconstexpr() DetID::mask_t sMasks[DetID::nDetectors] = ///< detectot masks 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::TST)), DetID::mask_t(math_utils::bit2Mask(DetID::CTP)), DetID::mask_t(math_utils::bit2Mask(DetID::FOC)) + #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)), DetID::mask_t(math_utils::bit2Mask(DetID::FCT)), DetID::mask_t(math_utils::bit2Mask(DetID::TF3)), - DetID::mask_t(math_utils::bit2Mask(DetID::RCH)), DetID::mask_t(math_utils::bit2Mask(DetID::MI3)), DetID::mask_t(math_utils::bit2Mask(DetID::ECL)) + DetID::mask_t(math_utils::bit2Mask(DetID::RCH)), DetID::mask_t(math_utils::bit2Mask(DetID::MI3)), DetID::mask_t(math_utils::bit2Mask(DetID::ECL)), DetID::mask_t(math_utils::bit2Mask(DetID::FD3)) #endif }; } // namespace detid_internal diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h index 6fb8825f7c395..ba6b853f7fb23 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h @@ -468,6 +468,9 @@ class EncodedBlocks /// total allocated size in bytes size_t size() const { return mRegistry.size; } + /// used part of total allocated size in bytes (output size) + size_t outputsize() const { return mRegistry.offsFreeStart; } + /// size remaining for additional data size_t getFreeSize() const { return mRegistry.getFreeSize(); } @@ -899,7 +902,7 @@ void EncodedBlocks::print(const std::string& prefix, int verbosity) con ndata += mBlocks[i].getNData(); nlit += mBlocks[i].getNLiterals(); } - LOG(info) << prefix << N << " blocks, input size: " << inpSize << ", output size: " << size() + LOG(info) << prefix << N << " blocks, input size: " << inpSize << ", output size: " << outputsize() << " NDictWords: " << ndict << " NDataWords: " << ndata << " NLiteralWords: " << nlit; } } @@ -929,9 +932,11 @@ CTFIOSize EncodedBlocks::decode(D_IT dest, // it const auto& md = mMetadata[slot]; LOGP(debug, "Slot{} | NStored={} Ndict={} nData={}, MD: messageLength:{} opt:{} min:{} max:{} offs:{} width:{} ", slot, block.getNStored(), block.getNDict(), block.getNData(), md.messageLength, (int)md.opt, md.min, md.max, md.literalsPackingOffset, md.literalsPackingWidth); + constexpr size_t word_size = sizeof(W); + if (ansVersion == ANSVersionCompat) { if (!block.getNStored()) { - return {0, md.getUncompressedSize(), md.getCompressedSize()}; + return {0, md.getUncompressedSize(), md.getCompressedSize() * word_size}; } if (md.opt == Metadata::OptStore::EENCODE) { return decodeCompatImpl(dest, slot, decoderExt); @@ -943,7 +948,7 @@ CTFIOSize EncodedBlocks::decode(D_IT dest, // it return decodeUnpackImpl(dest, slot); } if (!block.getNStored()) { - return {0, md.getUncompressedSize(), md.getCompressedSize()}; + return {0, md.getUncompressedSize(), md.getCompressedSize() * word_size}; } if (md.opt == Metadata::OptStore::EENCODE) { return decodeRansV1Impl(dest, slot, decoderExt); @@ -991,7 +996,7 @@ CTFIOSize EncodedBlocks::decodeCompatImpl(dst_IT dstBegin, int slot, co } else { getDecoder().process(block.getData() + block.getNData(), dstBegin, md.messageLength, NDecoderStreams); } - return {0, md.getUncompressedSize(), md.getCompressedSize()}; + return {0, md.getUncompressedSize(), md.getCompressedSize() * sizeof(W)}; }; template @@ -1045,7 +1050,7 @@ CTFIOSize EncodedBlocks::decodeRansV1Impl(dst_IT dstBegin, int slot, co } else { getDecoder().process(block.getData() + block.getNData(), dstBegin, md.messageLength, md.nStreams); } - return {0, md.getUncompressedSize(), md.getCompressedSize()}; + return {0, md.getUncompressedSize(), md.getCompressedSize() * sizeof(W)}; }; template @@ -1079,7 +1084,7 @@ CTFIOSize EncodedBlocks::decodeUnpackImpl(dst_IT dest, int slot) const } else { rans::unpack(srcIt, messageLength, dest, packingWidth, offset); } - return {0, md.getUncompressedSize(), md.getCompressedSize()}; + return {0, md.getUncompressedSize(), md.getCompressedSize() * sizeof(W)}; }; template @@ -1098,7 +1103,7 @@ CTFIOSize EncodedBlocks::decodeCopyImpl(dst_IT dest, int slot) const destPtr_t srcEnd = srcBegin + md.messageLength * sizeof(dest_t); std::copy(srcBegin, srcEnd, dest); - return {0, md.getUncompressedSize(), md.getCompressedSize()}; + return {0, md.getUncompressedSize(), md.getCompressedSize() * sizeof(W)}; }; ///_____________________________________________________________________________ @@ -1268,7 +1273,7 @@ o2::ctf::CTFIOSize EncodedBlocks::entropyCodeRANSCompat(const input_IT dataSize, nLiteralWords); - return {0, thisMetadata->getUncompressedSize(), thisMetadata->getCompressedSize()}; + return {0, thisMetadata->getUncompressedSize(), thisMetadata->getCompressedSize() * sizeof(W)}; } template @@ -1349,7 +1354,7 @@ CTFIOSize EncodedBlocks::encodeRANSV1External(const input_IT srcBegin, dataSize, literalsSize); - return {0, thisMetadata->getUncompressedSize(), thisMetadata->getCompressedSize()}; + return {0, thisMetadata->getUncompressedSize(), thisMetadata->getCompressedSize() * sizeof(W)}; }; template @@ -1458,7 +1463,7 @@ CTFIOSize EncodedBlocks::encodeRANSV1Inplace(const input_IT srcBegin, c dataSize, literalsSize); - return {0, thisMetadata->getUncompressedSize(), thisMetadata->getCompressedSize()}; + return {0, thisMetadata->getUncompressedSize(), thisMetadata->getCompressedSize() * sizeof(W)}; }; // namespace ctf template @@ -1491,7 +1496,7 @@ o2::ctf::CTFIOSize EncodedBlocks::pack(const input_IT srcBegin, const i } LOGP(debug, "StoreData {} bytes, offs: {}:{}", packedSize * sizeof(storageBuffer_t), thisBlock->getOffsData(), thisBlock->getOffsData() + packedSize * sizeof(storageBuffer_t)); - return {0, thisMetadata->getUncompressedSize(), thisMetadata->getCompressedSize()}; + return {0, thisMetadata->getUncompressedSize(), thisMetadata->getCompressedSize() * sizeof(W)}; }; template @@ -1513,7 +1518,7 @@ o2::ctf::CTFIOSize EncodedBlocks::store(const input_IT srcBegin, const *thisMetadata = detail::makeMetadataStore(messageLength, opt, nBufferElems); - return {0, thisMetadata->getUncompressedSize(), thisMetadata->getCompressedSize()}; + return {0, thisMetadata->getUncompressedSize(), thisMetadata->getCompressedSize() * sizeof(W)}; }; /// create a special EncodedBlocks containing only dictionaries made from provided vector of frequency tables diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/Metadata.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/Metadata.h index abf7561eb25a9..975522767dce1 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/Metadata.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/Metadata.h @@ -37,7 +37,7 @@ struct Metadata { size_t nLiterals = 0; // Number of samples that were stored as literals. uint8_t messageWordSize = 0; // size in Bytes of a symbol in the encoded message. uint8_t coderType = 0; // what type of CTF Coder is used? (32 vs 64 bit coders). - uint8_t streamSize = 0; // how many Bytes is the rANS encoder emmiting during a stream-out step. + uint8_t streamSize = 0; // number of Bytes emmitted during rANS stream out (ransCompat) or lower renorming bound (ransV1). uint8_t probabilityBits = 0; // The encoder renormed the distribution of source symbols to sum up to 2^probabilityBits. OptStore opt = OptStore::EENCODE; // The type of storage operation that was conducted. int32_t min = 0; // min symbol of the source dataset. @@ -48,8 +48,21 @@ struct Metadata { int nDataWords = 0; // Amount of words used to store the actual data. int nLiteralWords = 0; // Amount of words used to store literal (incompressible) samples. + /** + * @brief Uncompressed size of stored data in bytes + * + * @return size_t Uncompressed size in bytes + */ size_t getUncompressedSize() const { return messageLength * messageWordSize; } - size_t getCompressedSize() const { return (nDictWords + nDataWords + nLiteralWords) * streamSize; } + + /** + * @brief Size of the stored, compressed data in multiples of the underlying buffer word size + * + * @return size_t The size in multiples of the underlying buffer word size + * @warning This size is in number of words of the underlying storage buffer. + * Multiply with the size of the storage buffer type to get the correct size in bytes. + */ + size_t getCompressedSize() const { return nDictWords + nDataWords + nLiteralWords; } void clear() { nStreams = 0; diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/SimTraits.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/SimTraits.h index 8f9cbcfbdba43..37c4b790d181b 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/SimTraits.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/SimTraits.h @@ -99,7 +99,8 @@ class SimTraits /*TF3*/ VS{ "TF3Hit" }, /*RCH*/ VS{ "RCHHit" }, /*MI3*/ VS{ "MI3Hit" }, - /*ECL*/ VS{ "ECLHit" } + /*ECL*/ VS{ "ECLHit" }, + /*FD */ VS{ "FDHit" } #endif }; // clang-format on diff --git a/DataFormats/Detectors/Common/src/AlignParam.cxx b/DataFormats/Detectors/Common/src/AlignParam.cxx index 90f2a349607a1..2061726a29c66 100644 --- a/DataFormats/Detectors/Common/src/AlignParam.cxx +++ b/DataFormats/Detectors/Common/src/AlignParam.cxx @@ -12,12 +12,12 @@ /// \file AlignParam.cxx /// \brief Implementation of the base alignment parameters class -#include #include #include #include #include +#include "Framework/Logger.h" #include "DetectorsCommonDataFormats/AlignParam.h" using namespace o2::detectors; @@ -26,8 +26,9 @@ using namespace o2::detectors; AlignParam::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 - : mSymName(symname), mAlignableID(algID) + bool global, // global (preferable) or local delta definition + bool convertLocalToGlobal) // if local is provided, convert it to global + : mSymName(symname), mIsGlobal(global || convertLocalToGlobal), mAlignableID(algID) { /// standard constructor with 3 translation + 3 rotation parameters /// If the user explicitly sets the global variable to false then the @@ -35,23 +36,22 @@ 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) - if (global) { - setGlobalParams(x, y, z, psi, theta, phi); - } else { + setParams(x, y, z, psi, theta, phi); + if (!global && convertLocalToGlobal) { setLocalParams(x, y, z, psi, theta, phi); } } //___________________________________________________ -AlignParam::AlignParam(const char* symname, int algID, TGeoMatrix& m, bool global) - : mSymName(symname), mAlignableID(algID) +AlignParam::AlignParam(const char* symname, int algID, TGeoMatrix& m, bool global, bool convertLocalToGlobal) + : mSymName(symname), mIsGlobal(global || convertLocalToGlobal), mAlignableID(algID) { setTranslation(m); if (!setRotation(m)) { const double* rot = m.GetRotationMatrix(); throw std::runtime_error(fmt::format("Failed to extract roll-pitch-yall angles from [[{},{},{}], [{},{},{}], [{},{},{}] for {}", rot[0], rot[1], rot[2], rot[3], rot[4], rot[5], rot[6], rot[7], rot[8], symname)); } - if (!global && !setLocalParams(mX, mY, mZ, mPsi, mTheta, mPhi)) { + if (!global && convertLocalToGlobal && !setLocalParams(mX, mY, mZ, mPsi, mTheta, mPhi)) { throw std::runtime_error(fmt::format("Alignment creation for {} failed: geomManager is absent", symname)); } } @@ -223,6 +223,10 @@ bool AlignParam::createLocalMatrix(TGeoHMatrix& m) const // In case that the TGeo was not initialized or not closed, // returns false and the object parameters are not set. // + m = createMatrix(); + if (!mIsGlobal) { + return true; + } if (!gGeoManager || !gGeoManager->IsClosed()) { LOG(error) << "Can't get the local alignment object parameters! gGeoManager doesn't exist or it is still open!"; return false; @@ -247,7 +251,6 @@ bool AlignParam::createLocalMatrix(TGeoHMatrix& m) const LOG(error) << "Volume name or path " << symname << " is not valid!"; return false; } - m = createMatrix(); TGeoHMatrix gprime, gprimeinv; gprime = *node->GetMatrix(); gprimeinv = gprime.Inverse(); @@ -258,7 +261,7 @@ bool AlignParam::createLocalMatrix(TGeoHMatrix& m) const } //_____________________________________________________________________________ -bool AlignParam::applyToGeometry() const +bool AlignParam::applyToGeometry(int printLevel) const { /// Apply the current alignment object to the TGeo geometry /// This method returns FALSE if the symname of the object was not @@ -302,18 +305,26 @@ bool AlignParam::applyToGeometry() const } // double threshold = 0.001; + TGeoHMatrix* align = new TGeoHMatrix(createMatrix()); + if (mIsGlobal) { + align->Multiply(node->GetMatrix()); + align->MultiplyLeft(node->GetMatrix(node->GetLevel() - 1)->Inverse()); + } else { + align->MultiplyLeft(node->GetOriginalMatrix()); + } - TGeoHMatrix gprime = *node->GetMatrix(); - TGeoHMatrix align = createMatrix(); - gprime.MultiplyLeft(&align); - TGeoHMatrix* ginv = new TGeoHMatrix; // TGeoPhysicalNode takes and manages raw pointer, need naked new! - TGeoHMatrix* g = node->GetMatrix(node->GetLevel() - 1); - *ginv = g->Inverse(); - *ginv *= gprime; - - LOG(debug) << "Aligning volume " << symname; - - node->Align(ginv); + node->Align(align); + + if (getLevel() <= printLevel) { + LOGP(info, "{:*^100}", symname); + LOGP(info, " - Alignment parameter:"); + print(); + LOGP(info, " - Alignment matrix:"); + align->Print(); + LOGP(info, " - Node:"); + node->Print(); + LOGP(info, "{:~^100}", symname); + } return true; } @@ -347,8 +358,8 @@ int AlignParam::getLevel() const void AlignParam::print() const { // print parameters - 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()); + printf("%s (Lvl:%2d): %6d | %s | tra: X: %+e Y: %+e Z: %+e | pitch: %+e roll: %+e yaw: %e\n", getSymName().c_str(), getLevel(), getAlignableID(), (mIsGlobal) ? "G" : "L", + getX(), getY(), getZ(), getPsi(), getTheta(), getPhi()); } //_____________________________________________________________________________ @@ -359,6 +370,14 @@ void AlignParam::setGlobalParams(double x, double y, double z, double psi, doubl setRotation(psi, theta, phi); } +//_____________________________________________________________________________ +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); +} + //_____________________________________________________________________________ void AlignParam::setRotation(double psi, double theta, double phi) { diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/AnalysisCluster.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/AnalysisCluster.h index 758e0a1fa0b47..e19fd17dea2ce 100644 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/AnalysisCluster.h +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/AnalysisCluster.h @@ -182,6 +182,9 @@ class AnalysisCluster float getCoreEnergy() const { return mCoreEnergy; } void setCoreEnergy(float energy) { mCoreEnergy = energy; } + float getFCross() const { return mFCross; } + void setFCross(float fCross) { mFCross = fCross; } + /// /// Returns TLorentzVector with momentum of the cluster. Only valid for clusters /// identified as photons or pi0 (overlapped gamma) produced on the vertex @@ -223,12 +226,13 @@ class AnalysisCluster float mTime = 0.; ///< Time of the digit/cell with maximal energy deposition bool mIsExotic = false; //! +#include +#include #include #include -#include "Rtypes.h" namespace o2 { @@ -35,10 +35,15 @@ class CellLabel public: // CellLabel() = default; - /// \brief Constructor + /// \brief Constructor using std::vector by moving NOT copying /// \param labels list of mc labels /// \param amplitudeFractions list of amplitude fractions - CellLabel(const gsl::span labels, const gsl::span amplitudeFractions); + CellLabel(std::vector labels, std::vector amplitudeFractions); + + /// \brief Constructor using gsl::span + /// \param labels list of mc labels + /// \param amplitudeFractions list of amplitude fractions + CellLabel(gsl::span labels, gsl::span amplitudeFractions); // ~CellLabel() = default; // CellLabel(const CellLabel& clus) = default; @@ -52,13 +57,22 @@ class CellLabel /// \param index index which label to get int32_t GetLabel(size_t index) const { return mLabels[index]; } + /// \brief Getter for labels + std::vector GetLabels() const { return mLabels; } + /// \brief Getter for amplitude fraction /// \param index index which amplitude fraction to get float GetAmplitudeFraction(size_t index) const { return mAmplitudeFraction[index]; } + /// \brief Getter for amplitude fractions + std::vector GetAmplitudeFractions() const { return mAmplitudeFraction; } + + /// \brief Getter for label with leading amplitude fraction + int32_t GetLeadingMCLabel() const; + protected: - gsl::span mLabels; ///< List of MC particles that generated the cluster, ordered in deposited energy. - gsl::span mAmplitudeFraction; ///< List of the fraction of the cell energy coming from a MC particle. Index aligns with mLabels! + std::vector mLabels; ///< List of MC particles that generated the cluster, ordered in deposited energy. + std::vector mAmplitudeFraction; ///< List of the fraction of the cell energy coming from a MC particle. Index aligns with mLabels! }; } // namespace emcal diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EMCALChannelData.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EMCALChannelData.h deleted file mode 100644 index 3c014d37e6f9e..0000000000000 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EMCALChannelData.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file 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/src/CellLabel.cxx b/DataFormats/Detectors/EMCAL/src/CellLabel.cxx index 8dde7ea90c435..70a1a642c5449 100644 --- a/DataFormats/Detectors/EMCAL/src/CellLabel.cxx +++ b/DataFormats/Detectors/EMCAL/src/CellLabel.cxx @@ -12,12 +12,39 @@ /// \file CellLabel.cxx #include "DataFormatsEMCAL/CellLabel.h" +#include "fairlogger/Logger.h" +#include +#include +#include +#include +#include using namespace o2::emcal; -CellLabel::CellLabel(const gsl::span labels, const gsl::span amplitudeFractions) : mLabels(labels), mAmplitudeFraction(amplitudeFractions) +CellLabel::CellLabel(std::vector labels, std::vector amplitudeFractions) : mLabels(std::move(labels)), mAmplitudeFraction(std::move(amplitudeFractions)) { if (labels.size() != amplitudeFractions.size()) { LOG(error) << "Size of labels " << labels.size() << " does not match size of amplitude fraction " << amplitudeFractions.size() << " !"; } } + +CellLabel::CellLabel(gsl::span labels, gsl::span amplitudeFractions) : mLabels(labels.begin(), labels.end()), mAmplitudeFraction(amplitudeFractions.begin(), amplitudeFractions.end()) +{ + if (labels.size() != amplitudeFractions.size()) { + LOG(error) << "Size of labels " << labels.size() << " does not match size of amplitude fraction " << amplitudeFractions.size() << " !"; + } +} + +int32_t CellLabel::GetLeadingMCLabel() const +{ + size_t maxIndex = 0; + float maxFraction = mAmplitudeFraction[0]; + + for (size_t i = 1; i < mAmplitudeFraction.size(); ++i) { + if (mAmplitudeFraction[i] > maxFraction) { + maxFraction = mAmplitudeFraction[i]; + maxIndex = i; + } + } + return mLabels[maxIndex]; +} diff --git a/DataFormats/Detectors/FIT/FT0/CMakeLists.txt b/DataFormats/Detectors/FIT/FT0/CMakeLists.txt index e5331b7b739b2..f7d6a111f4348 100644 --- a/DataFormats/Detectors/FIT/FT0/CMakeLists.txt +++ b/DataFormats/Detectors/FIT/FT0/CMakeLists.txt @@ -47,4 +47,5 @@ o2_target_root_dictionary(DataFormatsFT0 include/DataFormatsFT0/GlobalOffsetsCalibrationObject.h include/DataFormatsFT0/SpectraInfoObject.h include/DataFormatsFT0/SlewingCoef.h + include/DataFormatsFT0/EventsPerBc.h ) diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/ChannelData.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/ChannelData.h index 9b3d6ec805604..dfe41525af480 100644 --- a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/ChannelData.h +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/ChannelData.h @@ -76,8 +76,8 @@ struct ChannelData { 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; } + [[nodiscard]] int16_t getTime() const { return CFDTime; } + [[nodiscard]] int16_t getAmp() const { return QTCAmpl; } bool operator==(ChannelData const& other) const { diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/EventsPerBc.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/EventsPerBc.h new file mode 100644 index 0000000000000..632eac342fdc9 --- /dev/null +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/EventsPerBc.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 _FT0_EVENTS_PER_BC_CALIB_OBJECT +#define _FT0_EVENTS_PER_BC_CALIB_OBJECT + +#include "CommonConstants/LHCConstants.h" +#include +#include +#include + +namespace o2::ft0 +{ +struct EventsPerBc { + std::array histogram; + + std::unique_ptr toTH1F(const char* name = "eventsPerBc") const + { + constexpr int N = o2::constants::lhc::LHCMaxBunches; + auto h = std::make_unique(name, name, N, 0, N); + for (int i = 0; i < N; ++i) { + h->SetBinContent(i + 1, histogram[i]); + } + return h; + } + + ClassDefNV(EventsPerBc, 1); +}; +} // namespace o2::ft0 +#endif \ No newline at end of file diff --git a/DataFormats/Detectors/FIT/FT0/src/DataFormatsFT0LinkDef.h b/DataFormats/Detectors/FIT/FT0/src/DataFormatsFT0LinkDef.h index 0d3491224180c..7f8c17a0cd191 100644 --- a/DataFormats/Detectors/FIT/FT0/src/DataFormatsFT0LinkDef.h +++ b/DataFormats/Detectors/FIT/FT0/src/DataFormatsFT0LinkDef.h @@ -56,4 +56,6 @@ #pragma link C++ class std::pair < std::vector < double>, std::vector < double>> + ; #pragma link C++ class o2::ft0::SlewingCoef + ; +#pragma link C++ class o2::ft0::EventsPerBc + ; + #endif diff --git a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/ChannelData.h b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/ChannelData.h index 054b336510c4f..29447dfa04202 100644 --- a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/ChannelData.h +++ b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/ChannelData.h @@ -76,8 +76,8 @@ struct ChannelData { 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; } + [[nodiscard]] int16_t getTime() const { return CFDTime; } + [[nodiscard]] int16_t getAmp() const { return QTCAmpl; } bool operator==(ChannelData const& other) const { diff --git a/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx b/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx index 39cc05d8a69e7..277466fb2e969 100644 --- a/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx +++ b/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx @@ -34,7 +34,7 @@ #include "ReconstructionDataFormats/TrackMCHMID.h" #include "DataFormatsITSMFT/TrkClusRef.h" #include "DataFormatsITSMFT/TopologyDictionary.h" -#include "ITSMFTBase/DPLAlpideParam.h" +#include "DataFormatsITSMFT/DPLAlpideParam.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 @@ -1440,8 +1440,7 @@ RecoContainer::GlobalIDSet RecoContainer::getSingleDetectorRefs(GTrackID gidx) c table[GTrackID::TRD] = parent0.getTrackRef(); // there is no standalone TRD track, so use the index for the ITSTPCTRD track array } else if (src == GTrackID::TPCTRDTOF) { const auto& parent0 = getTOFMatch(gidx); // TPCTRD : TOF - const auto& parent1 = getITSTPCTRDTrack(parent0.getTrackRef()); - const auto& parent2 = getTPCITSTrack(parent1.getRefGlobalTrackId()); + const auto& parent1 = getTPCTRDTrack(parent0.getTrackRef()); table[GTrackID::TPCTRD] = parent0.getTrackRef(); table[GTrackID::TPC] = parent1.getRefGlobalTrackId(); table[GTrackID::TOF] = {unsigned(parent0.getIdxTOFCl()), GTrackID::TOF}; @@ -1547,8 +1546,6 @@ const o2::dataformats::MCTruthContainer* RecoContainer::getE void RecoContainer::getTrackTimeITSTPCTRDTOF(GTrackID gid, float& t, float& tErr) const { const auto& match = getITSTPCTRDTOFMatches()[gid]; - auto gidx = match.getTrackRef(); // this should be corresponding ITS-TPC-TRD track - // const auto& tofCl = getTOFClusters()[match.getTOFClIndex()]; t = (match.getSignal() - match.getLTIntegralOut().getTOF(o2::track::PID::Pion)) * PS2MUS; // tof time in \mus, FIXME: account for time of flight to R TOF tErr = 0.010f; } @@ -1557,8 +1554,6 @@ void RecoContainer::getTrackTimeITSTPCTRDTOF(GTrackID gid, float& t, float& tErr void RecoContainer::getTrackTimeTPCTRDTOF(GTrackID gid, float& t, float& tErr) const { const auto& match = getTPCTRDTOFMatches()[gid]; - auto gidx = match.getTrackRef(); // this should be corresponding ITS-TPC-TRD track - // const auto& tofCl = getTOFClusters()[match.getTOFClIndex()]; t = (match.getSignal() - match.getLTIntegralOut().getTOF(o2::track::PID::Pion)) * PS2MUS; // tof time in \mus, FIXME: account for time of flight to R TOF tErr = 0.010f; } @@ -1567,8 +1562,6 @@ void RecoContainer::getTrackTimeTPCTRDTOF(GTrackID gid, float& t, float& tErr) c void RecoContainer::getTrackTimeITSTPCTOF(GTrackID gid, float& t, float& tErr) const { const auto& match = getITSTPCTOFMatches()[gid]; - auto gidx = match.getTrackRef(); // this should be corresponding ITS-TPC track - // const auto& tofCl = getTOFClusters()[match.getTOFClIndex()]; t = (match.getSignal() - match.getLTIntegralOut().getTOF(o2::track::PID::Pion)) * PS2MUS; // tof time in \mus, FIXME: account for time of flight to R TOF tErr = 0.010f; } @@ -1594,7 +1587,7 @@ void RecoContainer::getTrackTimeITSTPCTRD(GTrackID gid, float& t, float& tErr) c //________________________________________________________ void RecoContainer::getTrackTimeTPCTRD(GTrackID gid, float& t, float& tErr) const { - const auto trigTPCTRD = getITSTPCTRDTriggers(); + const auto trigTPCTRD = getTPCTRDTriggers(); // very slow: find the trigger this track belongs to for (const auto& trig : trigTPCTRD) { if (trig.getTrackRefs().getEntriesBound() > gid.getIndex()) { diff --git a/DataFormats/Detectors/ITSMFT/ITS/CMakeLists.txt b/DataFormats/Detectors/ITSMFT/ITS/CMakeLists.txt index 5a353881e27ba..f05979d749fc0 100644 --- a/DataFormats/Detectors/ITSMFT/ITS/CMakeLists.txt +++ b/DataFormats/Detectors/ITSMFT/ITS/CMakeLists.txt @@ -11,8 +11,12 @@ o2_add_library(DataFormatsITS SOURCES src/TrackITS.cxx + src/TimeEstBC.cxx PUBLIC_LINK_LIBRARIES O2::ReconstructionDataFormats + O2::SimulationDataFormat O2::DataFormatsITSMFT) o2_target_root_dictionary(DataFormatsITS - HEADERS include/DataFormatsITS/TrackITS.h) + HEADERS include/DataFormatsITS/TrackITS.h + include/DataFormatsITS/Vertex.h + include/DataFormatsITS/TimeEstBC.h) diff --git a/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TimeEstBC.h b/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TimeEstBC.h new file mode 100644 index 0000000000000..695d9aff42858 --- /dev/null +++ b/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TimeEstBC.h @@ -0,0 +1,103 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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_TRACKINGITS_TIMEESTBC_H_ +#define O2_TRACKINGITS_TIMEESTBC_H_ + +#include +#include +#include "CommonDataFormat/TimeStamp.h" +#include "GPUCommonRtypes.h" +#include "GPUCommonDef.h" +#include "GPUCommonMath.h" + +namespace o2::its +{ +// Time estimates are given in BC +// error needs to cover maximum 1 orbit +using TimeStampType = uint32_t; +using TimeStampErrorType = uint16_t; +// this is an symmetric time error [t0-tE, t0+tE] +using TimeStamp = o2::dataformats::TimeStampWithError; +// this is an asymmetric time interval [t0, t0+tE] used for internal calculations +class TimeEstBC : public o2::dataformats::TimeStampWithError +{ + using Base = o2::dataformats::TimeStampWithError; + + public: + GPUhdDefault() TimeEstBC() = default; + GPUhdi() TimeEstBC(TimeStampType t, TimeStampErrorType e) : Base(t, e) {} + + // convert to symmetric center+-half representation + GPUhdi() its::TimeStamp makeSymmetrical() const noexcept + { + const auto start = static_cast(this->getTimeStamp()); + const float half = (float)this->getTimeStampError() / 2.f; + return {start + half, half}; + } + + // check if timestamps overlap within their interval + GPUhdi() bool isCompatible(const TimeEstBC& o) const noexcept + { + return this->upper() > o.lower() && o.upper() > this->lower(); + } + + // check if this time interval is fully contained within o + GPUhdi() bool isContainedIn(const TimeEstBC& o) const noexcept + { + return this->lower() >= o.lower() && this->upper() <= o.upper(); + } + + GPUhdi() TimeEstBC& operator+=(const TimeEstBC& o) noexcept + { + add(o); + return *this; + } + + GPUhdi() TimeEstBC operator+(const TimeEstBC& o) const noexcept + { + TimeEstBC res = *this; + res += o; + return res; + } + + // upper bound of interval t0+tE + GPUhdi() TimeStampType upper() const noexcept + { + TimeStampType t = this->getTimeStamp(); + TimeStampType e = this->getTimeStampError(); + constexpr TimeStampType max = std::numeric_limits::max(); + return (t > (max - e)) ? max : t + e; + } + + // lower bound of interval t0 + GPUhdi() TimeStampType lower() const noexcept + { + return this->getTimeStamp(); + } + + private: + // intersect with the other timestamp + // this assumes already that both overlap + GPUhdi() void add(const TimeEstBC& o) noexcept + { + const TimeStampType lo = o2::gpu::CAMath::Max(this->lower(), o.lower()); + const TimeStampType hi = o2::gpu::CAMath::Min(this->upper(), o.upper()); + this->setTimeStamp(lo); + this->setTimeStampError(static_cast(hi - lo)); + } + + ClassDefNV(TimeEstBC, 1); +}; + +} // namespace o2::its + +#endif diff --git a/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h b/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h index e9931b89ecd4a..20fb7c63ebacd 100644 --- a/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h +++ b/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h @@ -1,4 +1,4 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. // See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. // All rights not expressly granted are reserved. // @@ -16,11 +16,12 @@ #ifndef ALICEO2_ITS_TRACKITS_H #define ALICEO2_ITS_TRACKITS_H -#include +#include #include "GPUCommonDef.h" #include "ReconstructionDataFormats/Track.h" #include "CommonDataFormat/RangeReference.h" +#include "DataFormatsITS/TimeEstBC.h" namespace o2 { @@ -35,8 +36,7 @@ namespace its class TrackITS : public o2::track::TrackParCov { enum UserBits { - kNextROF = 1 << 28, - kSharedClusters = 1 << 29 + kSharedClusters = 1 << 28 }; using Cluster = o2::itsmft::Cluster; @@ -93,6 +93,9 @@ class TrackITS : public o2::track::TrackParCov bool isBetter(const TrackITS& best, float maxChi2) const; + GPUhdi() auto& getTimeStamp() { return mTime; } + GPUhdi() const auto& getTimeStamp() const { return mTime; } + GPUhdi() o2::track::TrackParCov& getParamIn() { return *this; } GPUhdi() const o2::track::TrackParCov& getParamIn() const { return *this; } @@ -122,8 +125,6 @@ class TrackITS : public o2::track::TrackParCov } int getNFakeClusters() const; - void setNextROFbit(bool toggle = true) { mClusterSizes = toggle ? (mClusterSizes | kNextROF) : (mClusterSizes & ~kNextROF); } - bool hasHitInNextROF() const { return mClusterSizes & kNextROF; } void setSharedClusters(bool toggle = true) { mClusterSizes = toggle ? (mClusterSizes | kSharedClusters) : (mClusterSizes & ~kSharedClusters); } bool hasSharedClusters() const { return mClusterSizes & kSharedClusters; } @@ -157,9 +158,10 @@ class TrackITS : public o2::track::TrackParCov ClusRefs mClusRef; ///< references on clusters float mChi2 = 0.; ///< Chi2 for this track uint32_t mPattern = 0; ///< layers pattern - unsigned int mClusterSizes = 0u; + uint32_t mClusterSizes = 0u; ///< 4bit packed cluster sizes + TimeStamp mTime; ///< track time stamp with error in BC since start of TF, symmetrical - ClassDefNV(TrackITS, 6); + ClassDefNV(TrackITS, 7); }; class TrackITSExt : public TrackITS @@ -169,15 +171,13 @@ class TrackITSExt : public TrackITS static constexpr int MaxClusters = 16; /// Prepare for overlaps and new detector configurations using TrackITS::TrackITS; // inherit base constructors - GPUh() TrackITSExt(o2::track::TrackParCov&& parCov, short ncl, float chi2, - o2::track::TrackParCov&& outer, o2::gpu::gpustd::array cls) + GPUh() TrackITSExt(o2::track::TrackParCov&& parCov, short ncl, float chi2, o2::track::TrackParCov&& outer, std::array cls) : TrackITS(parCov, chi2, outer), mIndex{cls} { setNumberOfClusters(ncl); } - GPUh() TrackITSExt(o2::track::TrackParCov& parCov, short ncl, float chi2, std::uint32_t rof, - o2::track::TrackParCov& outer, o2::gpu::gpustd::array cls) + GPUh() TrackITSExt(o2::track::TrackParCov& parCov, short ncl, float chi2, std::uint32_t rof, o2::track::TrackParCov& outer, std::array cls) : TrackITS(parCov, chi2, outer), mIndex{cls} { setNumberOfClusters(ncl); @@ -192,7 +192,12 @@ class TrackITSExt : public TrackITS getClusterRefs().setEntries(ncl); } - GPUhdi() const int& getClusterIndex(int lr) const { return mIndex[lr]; } + GPUhdi() int getClusterIndex(int lr) const { return mIndex[lr]; } + + GPUh() int getFirstLayerClusterIndex() const + { + return getClusterIndex(getFirstClusterLayer()); + } GPUhdi() void setExternalClusterIndex(int layer, int idx, bool newCluster = false) { @@ -205,14 +210,41 @@ class TrackITSExt : public TrackITS mIndex[layer] = idx; } - GPUh() o2::gpu::gpustd::array& getClusterIndexes() + GPUh() std::array& getClusterIndexes() { return mIndex; } +#ifndef GPUCA_GPUCODE + // build order-independent hash via the external cluster idx (unique within a TF) for the selected layers + // cluster indices are either sorted inward or outward + size_t hash(uint16_t layerMask = 0xFFFF, bool inward = true) const noexcept + { + size_t h1 = 0, h2 = 0; + int from = (int)getLastClusterLayer(), to = -1, step = -1; + if (inward) { + from = (int)getFirstClusterLayer(); + to = MaxClusters; + step = 1; + } + // clusters are stored continously but they do not necesarrily correspond to the layers + for (int layer = from, slot{0}; layer != to; layer += step) { + if (hasHitOnLayer(layer)) { + int idx = mIndex[slot++]; + if (layerMask & (uint16_t(1) << layer)) { + size_t v = std::hash{}(idx); + h1 ^= v; + h2 += v * 0x9e3779b97f4a7c15ULL; // boost's hash_combine + } + } + } + return h1 ^ (h2 << 1); + } +#endif + private: - o2::gpu::gpustd::array mIndex = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; ///< Indices of associated clusters - ClassDefNV(TrackITSExt, 2); + std::array mIndex = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; ///< Indices of associated clusters + ClassDefNV(TrackITSExt, 3); }; } // namespace its } // namespace o2 diff --git a/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/Vertex.h b/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/Vertex.h new file mode 100644 index 0000000000000..1e4ed03b753eb --- /dev/null +++ b/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/Vertex.h @@ -0,0 +1,42 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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_TRACKINGITS_VERTEX_H_ +#define O2_TRACKINGITS_VERTEX_H_ + +#include "GPUCommonDef.h" +#ifndef GPUCA_GPUCODE_DEVICE +#include +#endif +#include "ReconstructionDataFormats/Vertex.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "DataFormatsITS/TimeEstBC.h" + +namespace o2::its +{ +// NOTE: this uses the internal asymmetrical time reprenstation! +using Vertex = o2::dataformats::Vertex; +using VertexLabel = std::pair; +} // namespace o2::its + +#ifndef GPUCA_GPUCODE_DEVICE +/// Defining ITS Vertex explicitly as messageable +namespace o2::framework +{ +template +struct is_messageable; +template <> +struct is_messageable> : std::true_type { +}; +} // namespace o2::framework +#endif + +#endif diff --git a/DataFormats/Detectors/ITSMFT/ITS/src/DataFormatsITSLinkDef.h b/DataFormats/Detectors/ITSMFT/ITS/src/DataFormatsITSLinkDef.h index 91a71847148fb..a0d5b25c65b70 100644 --- a/DataFormats/Detectors/ITSMFT/ITS/src/DataFormatsITSLinkDef.h +++ b/DataFormats/Detectors/ITSMFT/ITS/src/DataFormatsITSLinkDef.h @@ -14,7 +14,14 @@ #pragma link off all globals; #pragma link off all classes; #pragma link off all functions; + #pragma link C++ class o2::its::TrackITS + ; #pragma link C++ class std::vector < o2::its::TrackITS> + ; +#pragma link C++ class o2::its::TimeEstBC + ; +#pragma link C++ class std::vector < o2::its::TimeEstBC> + ; + +#pragma link C++ class o2::dataformats::Vertex < o2::its::TimeEstBC> + ; +#pragma link C++ class std::vector < o2::dataformats::Vertex < o2::its::TimeEstBC>> + ; + #endif diff --git a/DataFormats/Detectors/ITSMFT/ITS/src/TimeEstBC.cxx b/DataFormats/Detectors/ITSMFT/ITS/src/TimeEstBC.cxx new file mode 100644 index 0000000000000..3af299cf74d25 --- /dev/null +++ b/DataFormats/Detectors/ITSMFT/ITS/src/TimeEstBC.cxx @@ -0,0 +1,13 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsITS/TimeEstBC.h" +ClassImp(o2::its::TimeEstBC); \ No newline at end of file diff --git a/DataFormats/Detectors/ITSMFT/common/CMakeLists.txt b/DataFormats/Detectors/ITSMFT/common/CMakeLists.txt index 62fc09ffcad00..a619f8ad0081d 100644 --- a/DataFormats/Detectors/ITSMFT/common/CMakeLists.txt +++ b/DataFormats/Detectors/ITSMFT/common/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# Copyright 2019-2026 CERN and copyright holders of ALICE O2. # See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. # All rights not expressly granted are reserved. # @@ -18,17 +18,23 @@ o2_add_library(DataFormatsITSMFT src/ClusterPattern.cxx src/ClusterTopology.cxx src/TopologyDictionary.cxx + src/TimeDeadMap.cxx src/CTF.cxx + src/DPLAlpideParam.cxx + src/DPLAlpideParamInitializer.cxx PUBLIC_LINK_LIBRARIES O2::ITSMFTBase + O2::DetectorsCommonDataFormats O2::ReconstructionDataFormats + O2::CommonUtils Microsoft.GSL::GSL) o2_target_root_dictionary(DataFormatsITSMFT HEADERS include/DataFormatsITSMFT/ROFRecord.h - include/DataFormatsITSMFT/Digit.h - include/DataFormatsITSMFT/GBTCalibData.h - include/DataFormatsITSMFT/NoiseMap.h - include/DataFormatsITSMFT/TimeDeadMap.h + include/DataFormatsITSMFT/Digit.h + include/DataFormatsITSMFT/DPLAlpideParam.h + include/DataFormatsITSMFT/GBTCalibData.h + include/DataFormatsITSMFT/NoiseMap.h + include/DataFormatsITSMFT/TimeDeadMap.h include/DataFormatsITSMFT/Cluster.h include/DataFormatsITSMFT/CompCluster.h include/DataFormatsITSMFT/ClusterPattern.h diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/CTF.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/CTF.h index 314523aa878ba..0510b6df5225c 100644 --- a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/CTF.h +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/CTF.h @@ -36,7 +36,9 @@ struct CTFHeader : public o2::ctf::CTFDictHeader { 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, 2); + uint8_t maxStreams = 1; /// Number of streams per TF (== NLayers for staggered ITS/MFT readout, 1 for non-staggered one) + uint8_t streamID = 0; /// ID of the stream (0:maxStreams-1) + ClassDefNV(CTFHeader, 3); }; /// Compressed but not yet entropy-encoded clusters diff --git a/Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/DPLAlpideParam.h similarity index 61% rename from Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h rename to DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/DPLAlpideParam.h index bc3b3dbde53b0..a06ba0745edbd 100644 --- a/Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/DPLAlpideParam.h @@ -9,8 +9,8 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef ALICEO2_ITSMFTDPLBASEPARAM_H_ -#define ALICEO2_ITSMFTDPLBASEPARAM_H_ +#ifndef ALICEO2_ITSMFTALPIDEPARAM_H_ +#define ALICEO2_ITSMFTALPIDEPARAM_H_ #include "DetectorsCommonDataFormats/DetID.h" #include "CommonUtils/ConfigurableParam.h" @@ -26,17 +26,30 @@ constexpr float DEFStrobeDelay = o2::constants::lhc::LHCBunchSpacingNS * 4; // ~ template struct DPLAlpideParam : public o2::conf::ConfigurableParamHelper> { + static constexpr int getNLayers() + { + return N == o2::detectors::DetID::ITS ? 7 : 10; + } static constexpr std::string_view getParamName() { return N == o2::detectors::DetID::ITS ? ParamName[0] : ParamName[1]; } - int roFrameLengthInBC = DEFROFLengthBC(); ///< ROF length in BC for continuos mode - float roFrameLengthTrig = DEFROFLengthTrig(); ///< length of RO frame in ns for triggered mode - float strobeDelay = DEFStrobeDelay; ///< strobe start (in ns) wrt ROF start - float strobeLengthCont = -1.; ///< if < 0, full ROF length - delay - float strobeLengthTrig = 100.; ///< length of the strobe in ns (sig. over threshold checked in this window only) - int roFrameBiasInBC = DEFROFBiasInBC(); ///< bias of the start of ROF wrt orbit start: t_irof = (irof*roFrameLengthInBC + roFrameBiasInBC)*BClengthMUS + + int roFrameLengthInBC = DEFROFLengthBC(); ///< ROF length in BC for continuous mode + float roFrameLengthTrig = DEFROFLengthTrig(); ///< length of RO frame in ns for triggered mode + float strobeDelay = DEFStrobeDelay; ///< strobe start (in ns) wrt ROF start + float strobeLengthCont = -1.; ///< if < 0, full ROF length - delay + float strobeLengthTrig = 100.; ///< length of the strobe in ns (sig. over threshold checked in this window only) + int roFrameBiasInBC = DEFROFBiasInBC(); ///< bias of the start of ROF wrt orbit start: t_irof = (irof*roFrameLengthInBC + roFrameBiasInBC)*BClengthMUS + int roFrameLayerLengthInBC[getNLayers()] = {}; ///< staggering ROF length in BC for continuous mode per layer + int roFrameLayerBiasInBC[getNLayers()] = {}; ///< staggering ROF bias in BC for continuous mode per layer + int roFrameLayerDelayInBC[getNLayers()] = {}; ///< staggering ROF delay in BC for continuous mode per layer + + // get ROF length for any layer + int getROFLengthInBC(int layer) const noexcept { return roFrameLayerLengthInBC[layer] ? roFrameLayerLengthInBC[layer] : roFrameLengthInBC; } + int getROFBiasInBC(int layer) const noexcept { return roFrameLayerBiasInBC[layer] ? roFrameLayerBiasInBC[layer] : roFrameBiasInBC; } + int getROFDelayInBC(int layer) const noexcept { return roFrameLayerDelayInBC[layer] ? roFrameLayerDelayInBC[layer] : 0; } // boilerplate stuff + make principal key O2ParamDef(DPLAlpideParam, getParamName().data()); @@ -46,7 +59,7 @@ struct DPLAlpideParam : public o2::conf::ConfigurableParamHelper + +namespace o2 +{ +namespace framework +{ +class ConfigParamSpec; +class ConfigContext; +} // namespace framework +namespace itsmft +{ + +struct DPLAlpideParamInitializer { + static constexpr char stagITSOpt[] = "enable-its-staggering"; + static constexpr char stagMFTOpt[] = "enable-mft-staggering"; + static constexpr bool stagDef = false; + + // DPL workflow options for staggering + static void addConfigOption(std::vector& opts); + static void addITSConfigOption(std::vector& opts); + static bool isITSStaggeringEnabled(o2::framework::ConfigContext const& cfgc); + static void addMFTConfigOption(std::vector& opts); + static bool isMFTStaggeringEnabled(o2::framework::ConfigContext const& cfgc); +}; + +} // namespace itsmft +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TimeDeadMap.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TimeDeadMap.h index a0b214f705d7c..6c7c01dc888b7 100644 --- a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TimeDeadMap.h +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TimeDeadMap.h @@ -14,11 +14,12 @@ #ifndef ALICEO2_ITSMFT_TIMEDEADMAP_H #define ALICEO2_ITSMFT_TIMEDEADMAP_H -#include "Rtypes.h" -#include "DetectorsCommonDataFormats/DetID.h" -#include -#include +#include + +#include #include +#include +#include namespace o2 { @@ -26,6 +27,8 @@ namespace o2 namespace itsmft { +class NoiseMap; + class TimeDeadMap { public: @@ -56,96 +59,17 @@ class TimeDeadMap mStaticDeadMap.clear(); } - void decodeMap(o2::itsmft::NoiseMap& noisemap) - { // for static part only - if (mMAP_VERSION == "3") { - LOG(error) << "Trying to decode static part of deadmap version " << mMAP_VERSION << ". Not implemented, doing nothing."; - return; - } - for (int iel = 0; iel < mStaticDeadMap.size(); iel++) { - uint16_t w = mStaticDeadMap[iel]; - noisemap.maskFullChip(w & 0x7FFF); - if (w & 0x8000) { - for (int w2 = (w & 0x7FFF) + 1; w2 < mStaticDeadMap.at(iel + 1); w2++) { - noisemap.maskFullChip(w2); - } - } - } - } - - void decodeMap(unsigned long orbit, o2::itsmft::NoiseMap& noisemap, bool includeStaticMap = true, long orbitGapAllowed = 330000) - { // for time-dependent and (optionally) static part. Use orbitGapAllowed = -1 to ignore check on orbit difference - - if (mMAP_VERSION != "3" && mMAP_VERSION != "4") { - LOG(error) << "Trying to decode time-dependent deadmap version " << mMAP_VERSION << ". Not implemented, doing nothing."; - return; - } - - if (mEvolvingDeadMap.empty()) { - LOG(warning) << "Time-dependent dead map is empty. Doing nothing."; - return; - } - - std::vector closestVec; - long dT = getMapAtOrbit(orbit, closestVec); - - if (orbitGapAllowed >= 0 && std::abs(dT) > orbitGapAllowed) { - LOG(warning) << "Requested orbit " << orbit << ", found " << orbit - dT << ". Orbit gap is too high, skipping time-dependent map."; - closestVec.clear(); - } - - // add static part if requested. something may be masked twice - if (includeStaticMap && mMAP_VERSION != "3") { - closestVec.insert(closestVec.end(), mStaticDeadMap.begin(), mStaticDeadMap.end()); - } - - // vector encoding: if 1<<15 = 0x8000 is set, the word encodes the first element of a range, with mask (1<<15)-1 = 0x7FFF. The last element of the range is the next in the vector. - - for (int iel = 0; iel < closestVec.size(); iel++) { - uint16_t w = closestVec.at(iel); - noisemap.maskFullChip(w & 0x7FFF); - if (w & 0x8000) { - for (int w2 = (w & 0x7FFF) + 1; w2 < closestVec.at(iel + 1); w2++) { - noisemap.maskFullChip(w2); - } - } - } - }; - + void decodeMap(NoiseMap& noisemap) const; + void decodeMap(unsigned long orbit, o2::itsmft::NoiseMap& noisemap, bool includeStaticMap = true, long orbitGapAllowed = 330000) const; std::string getMapVersion() const { return mMAP_VERSION; }; unsigned long getEvolvingMapSize() const { return mEvolvingDeadMap.size(); }; - - std::vector getEvolvingMapKeys() - { - std::vector keys; - std::transform(mEvolvingDeadMap.begin(), mEvolvingDeadMap.end(), std::back_inserter(keys), - [](const auto& O) { return O.first; }); - return keys; - } - - void getStaticMap(std::vector& mmap) { mmap = mStaticDeadMap; }; - - long getMapAtOrbit(unsigned long orbit, std::vector& mmap) - { // fills mmap and returns requested_orbit - found_orbit. Found orbit is the highest key lower or equal to the requested one - if (mEvolvingDeadMap.empty()) { - LOG(warning) << "Requested orbit " << orbit << "from an empty time-dependent map. Doing nothing"; - return (long)orbit; - } - auto closest = mEvolvingDeadMap.upper_bound(orbit); - if (closest != mEvolvingDeadMap.begin()) { - --closest; - mmap = closest->second; - return (long)orbit - closest->first; - } else { - mmap = mEvolvingDeadMap.begin()->second; - return (long)(orbit)-mEvolvingDeadMap.begin()->first; - } - } - + std::vector getEvolvingMapKeys() const; + void getStaticMap(std::vector& mmap) const { mmap = mStaticDeadMap; }; + long getMapAtOrbit(unsigned long orbit, std::vector& mmap) const; void setMapVersion(std::string version) { mMAP_VERSION = version; }; - bool isDefault() { return mIsDefaultObject; }; + bool isDefault() const { return mIsDefaultObject; }; void setAsDefault(bool isdef = true) { mIsDefaultObject = isdef; }; private: diff --git a/Detectors/ITSMFT/common/base/src/DPLAlpideParam.cxx b/DataFormats/Detectors/ITSMFT/common/src/DPLAlpideParam.cxx similarity index 82% rename from Detectors/ITSMFT/common/base/src/DPLAlpideParam.cxx rename to DataFormats/Detectors/ITSMFT/common/src/DPLAlpideParam.cxx index 1cb9bdf997d68..205f8a008a661 100644 --- a/Detectors/ITSMFT/common/base/src/DPLAlpideParam.cxx +++ b/DataFormats/Detectors/ITSMFT/common/src/DPLAlpideParam.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. // See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. // All rights not expressly granted are reserved. // @@ -9,15 +9,12 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "ITSMFTBase/DPLAlpideParam.h" +#include "DataFormatsITSMFT/DPLAlpideParam.h" -namespace o2 -{ -namespace itsmft +namespace o2::itsmft { // this makes sure that the constructor of the parameters is statically called // so that these params are part of the parameter database static auto& sAlpideParamITS = o2::itsmft::DPLAlpideParam::Instance(); static auto& sAlpideParamMFT = o2::itsmft::DPLAlpideParam::Instance(); -} // namespace itsmft -} // namespace o2 +} // namespace o2::itsmft diff --git a/DataFormats/Detectors/ITSMFT/common/src/DPLAlpideParamInitializer.cxx b/DataFormats/Detectors/ITSMFT/common/src/DPLAlpideParamInitializer.cxx new file mode 100644 index 0000000000000..715ec5d90b813 --- /dev/null +++ b/DataFormats/Detectors/ITSMFT/common/src/DPLAlpideParamInitializer.cxx @@ -0,0 +1,46 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" +#include "Framework/ConfigParamsHelper.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/ConfigContext.h" + +namespace o2::itsmft +{ + +void DPLAlpideParamInitializer::addConfigOption(std::vector& opts) +{ + addITSConfigOption(opts); + addMFTConfigOption(opts); +} + +void DPLAlpideParamInitializer::addITSConfigOption(std::vector& opts) +{ + o2::framework::ConfigParamsHelper::addOptionIfMissing(opts, {stagITSOpt, o2::framework::VariantType::Bool, stagDef, {"enable per layer ITS in&out-put for staggered readout"}}); +} + +void DPLAlpideParamInitializer::addMFTConfigOption(std::vector& opts) +{ + o2::framework::ConfigParamsHelper::addOptionIfMissing(opts, {stagMFTOpt, o2::framework::VariantType::Bool, stagDef, {"enable per layer MFT in&out-put for staggered readout"}}); +} + +bool DPLAlpideParamInitializer::isITSStaggeringEnabled(const o2::framework::ConfigContext& cfgc) +{ + return cfgc.options().get(stagITSOpt); +} + +bool DPLAlpideParamInitializer::isMFTStaggeringEnabled(const o2::framework::ConfigContext& cfgc) +{ + return cfgc.options().get(stagMFTOpt); +} + +} // namespace o2::itsmft diff --git a/DataFormats/Detectors/ITSMFT/common/src/ITSMFTDataFormatsLinkDef.h b/DataFormats/Detectors/ITSMFT/common/src/ITSMFTDataFormatsLinkDef.h index fc67fdf028436..1b1918b46c9d4 100644 --- a/DataFormats/Detectors/ITSMFT/common/src/ITSMFTDataFormatsLinkDef.h +++ b/DataFormats/Detectors/ITSMFT/common/src/ITSMFTDataFormatsLinkDef.h @@ -15,6 +15,11 @@ #pragma link off all classes; #pragma link off all functions; +#pragma link C++ class o2::itsmft::DPLAlpideParam < o2::detectors::DetID::ITS> + ; +#pragma link C++ class o2::itsmft::DPLAlpideParam < o2::detectors::DetID::MFT> + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::itsmft::DPLAlpideParam < o2::detectors::DetID::ITS>> + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::itsmft::DPLAlpideParam < o2::detectors::DetID::MFT>> + ; + #pragma link C++ class o2::itsmft::Digit + ; #pragma link C++ class o2::itsmft::NoiseMap + ; #pragma link C++ class o2::itsmft::TimeDeadMap + ; diff --git a/DataFormats/Detectors/ITSMFT/common/src/ROFRecord.cxx b/DataFormats/Detectors/ITSMFT/common/src/ROFRecord.cxx index 83b46f8798fc9..8dbde0d580efc 100644 --- a/DataFormats/Detectors/ITSMFT/common/src/ROFRecord.cxx +++ b/DataFormats/Detectors/ITSMFT/common/src/ROFRecord.cxx @@ -9,20 +9,22 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "DataFormatsITSMFT/ROFRecord.h" #include -#include "fmt/format.h" +#include + +#include "DataFormatsITSMFT/ROFRecord.h" +#include "Framework/Logger.h" using namespace o2::itsmft; std::string ROFRecord::asString() const { - return fmt::format("ROF: {} | {} entries starting from {}", mROFrame, getNEntries(), getFirstEntry()); + return std::format("ROF: {} | {} entries starting from {} | IR: {}", mROFrame, getNEntries(), getFirstEntry(), mBCData.asString()); } void ROFRecord::print() const { - std::cout << this << "\n\t" << mBCData << std::endl; + LOG(info) << asString(); } std::ostream& operator<<(std::ostream& stream, ROFRecord const& rec) @@ -33,12 +35,12 @@ std::ostream& operator<<(std::ostream& stream, ROFRecord const& rec) std::string MC2ROFRecord::asString() const { - return fmt::format("MCEventID: {} ROFs: {}-{} Entry in ROFRecords: {}", eventRecordID, minROF, maxROF, rofRecordID); + return std::format("MCEventID: {} ROFs: {}-{} Entry in ROFRecords: {}", eventRecordID, minROF, maxROF, rofRecordID); } void MC2ROFRecord::print() const { - std::cout << this << std::endl; + LOG(info) << asString(); } std::ostream& operator<<(std::ostream& stream, MC2ROFRecord const& rec) diff --git a/DataFormats/Detectors/ITSMFT/common/src/TimeDeadMap.cxx b/DataFormats/Detectors/ITSMFT/common/src/TimeDeadMap.cxx new file mode 100644 index 0000000000000..e3df8e7f91f86 --- /dev/null +++ b/DataFormats/Detectors/ITSMFT/common/src/TimeDeadMap.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 TimeDeadMap.cxx +/// \brief Implementation of the time-dependent map + +#include "DataFormatsITSMFT/TimeDeadMap.h" +#include "DataFormatsITSMFT/NoiseMap.h" +#include "Framework/Logger.h" + +using namespace o2::itsmft; + +void TimeDeadMap::decodeMap(o2::itsmft::NoiseMap& noisemap) const +{ // for static part only + if (mMAP_VERSION == "3") { + LOG(error) << "Trying to decode static part of deadmap version " << mMAP_VERSION << ". Not implemented, doing nothing."; + return; + } + for (int iel = 0; iel < mStaticDeadMap.size(); iel++) { + uint16_t w = mStaticDeadMap[iel]; + noisemap.maskFullChip(w & 0x7FFF); + if (w & 0x8000) { + for (int w2 = (w & 0x7FFF) + 1; w2 < mStaticDeadMap.at(iel + 1); w2++) { + noisemap.maskFullChip(w2); + } + } + } +} + +void TimeDeadMap::decodeMap(unsigned long orbit, o2::itsmft::NoiseMap& noisemap, bool includeStaticMap, long orbitGapAllowed) const +{ // for time-dependent and (optionally) static part. Use orbitGapAllowed = -1 to ignore check on orbit difference + + if (mMAP_VERSION != "3" && mMAP_VERSION != "4") { + LOG(error) << "Trying to decode time-dependent deadmap version " << mMAP_VERSION << ". Not implemented, doing nothing."; + return; + } + + if (mEvolvingDeadMap.empty()) { + LOG(warning) << "Time-dependent dead map is empty. Doing nothing."; + return; + } + + std::vector closestVec; + long dT = getMapAtOrbit(orbit, closestVec); + + if (orbitGapAllowed >= 0 && std::abs(dT) > orbitGapAllowed) { + LOG(warning) << "Requested orbit " << orbit << ", found " << orbit - dT << ". Orbit gap is too high, skipping time-dependent map."; + closestVec.clear(); + } + + // add static part if requested. something may be masked twice + if (includeStaticMap && mMAP_VERSION != "3") { + closestVec.insert(closestVec.end(), mStaticDeadMap.begin(), mStaticDeadMap.end()); + } + + // vector encoding: if 1<<15 = 0x8000 is set, the word encodes the first element of a range, with mask (1<<15)-1 = 0x7FFF. The last element of the range is the next in the vector. + + for (int iel = 0; iel < closestVec.size(); iel++) { + uint16_t w = closestVec.at(iel); + noisemap.maskFullChip(w & 0x7FFF); + if (w & 0x8000) { + for (int w2 = (w & 0x7FFF) + 1; w2 < closestVec.at(iel + 1); w2++) { + noisemap.maskFullChip(w2); + } + } + } +} + +std::vector TimeDeadMap::getEvolvingMapKeys() const +{ + std::vector keys; + std::transform(mEvolvingDeadMap.begin(), mEvolvingDeadMap.end(), std::back_inserter(keys), + [](const auto& O) { return O.first; }); + return keys; +} + +long TimeDeadMap::getMapAtOrbit(unsigned long orbit, std::vector& mmap) const +{ // fills mmap and returns requested_orbit - found_orbit. Found orbit is the highest key lower or equal to the requested one + if (mEvolvingDeadMap.empty()) { + LOG(warning) << "Requested orbit " << orbit << "from an empty time-dependent map. Doing nothing"; + return (long)orbit; + } + auto closest = mEvolvingDeadMap.upper_bound(orbit); + if (closest != mEvolvingDeadMap.begin()) { + --closest; + mmap = closest->second; + return (long)orbit - closest->first; + } else { + mmap = mEvolvingDeadMap.begin()->second; + return (long)(orbit)-mEvolvingDeadMap.begin()->first; + } +} diff --git a/DataFormats/Detectors/TOF/CMakeLists.txt b/DataFormats/Detectors/TOF/CMakeLists.txt index 03dbd9275edf9..4d41167f7bf1d 100644 --- a/DataFormats/Detectors/TOF/CMakeLists.txt +++ b/DataFormats/Detectors/TOF/CMakeLists.txt @@ -9,6 +9,14 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +o2_add_library(DataFormatsParamTOF + SOURCES src/ParameterContainers.cxx + PUBLIC_LINK_LIBRARIES O2::FrameworkLogger) + + +o2_target_root_dictionary(DataFormatsParamTOF + HEADERS include/DataFormatsTOF/ParameterContainers.h) + o2_add_library(DataFormatsTOF SOURCES src/Cluster.cxx src/CalibInfoTOFshort.cxx @@ -16,13 +24,13 @@ o2_add_library(DataFormatsTOF src/CalibLHCphaseTOF.cxx src/CalibTimeSlewingParamTOF.cxx src/CTF.cxx - src/ParameterContainers.cxx src/CalibInfoCluster.cxx src/CosmicInfo.cxx src/Diagnostic.cxx src/TOFFEElightInfo.cxx PUBLIC_LINK_LIBRARIES O2::ReconstructionDataFormats O2::GPUCommon + O2::DataFormatsParamTOF Boost::serialization) o2_target_root_dictionary(DataFormatsTOF @@ -34,7 +42,6 @@ o2_target_root_dictionary(DataFormatsTOF include/DataFormatsTOF/RawDataFormat.h include/DataFormatsTOF/CompressedDataFormat.h include/DataFormatsTOF/CTF.h - include/DataFormatsTOF/ParameterContainers.h include/DataFormatsTOF/CalibInfoCluster.h include/DataFormatsTOF/CosmicInfo.h include/DataFormatsTOF/TOFFEElightInfo.h diff --git a/DataFormats/Detectors/TOF/include/DataFormatsTOF/Cluster.h b/DataFormats/Detectors/TOF/include/DataFormatsTOF/Cluster.h index f36150e18fbbc..37d3ca23ddb35 100644 --- a/DataFormats/Detectors/TOF/include/DataFormatsTOF/Cluster.h +++ b/DataFormats/Detectors/TOF/include/DataFormatsTOF/Cluster.h @@ -49,7 +49,8 @@ class Cluster : public o2::BaseCluster kDownRight = 4, // 2^4, 5th bit kDown = 5, // 2^5, 6th bit kDownLeft = 6, // 2^6, 7th bit - kLeft = 7 }; // 2^7, 8th bit + kLeft = 7 // 2^7, 8th bit + }; Cluster() = default; @@ -57,6 +58,9 @@ class Cluster : public o2::BaseCluster ~Cluster() = default; + bool isInNominalSector() const { return mInNominalSector; } + void setInNominalSector(bool v = true) { mInNominalSector = v; } + std::int8_t getSector() const { return getCount(); } void setSector(std::int8_t value) { setCount(value); } @@ -158,9 +162,10 @@ class Cluster : public o2::BaseCluster double mDigitInfoT[6] = {0., 0., 0., 0., 0., 0.}; float mDigitInfoTOT[6] = {0., 0., 0., 0., 0., 0.}; float mTgeant = 0.0; + bool mInNominalSector = false; double mT0true = 0.0; - ClassDefNV(Cluster, 5); + ClassDefNV(Cluster, 6); }; #ifndef GPUCA_GPUCODE diff --git a/DataFormats/Detectors/TOF/include/DataFormatsTOF/Diagnostic.h b/DataFormats/Detectors/TOF/include/DataFormatsTOF/Diagnostic.h index 8adcdb63e9d21..028da04b3ef70 100644 --- a/DataFormats/Detectors/TOF/include/DataFormatsTOF/Diagnostic.h +++ b/DataFormats/Detectors/TOF/include/DataFormatsTOF/Diagnostic.h @@ -44,6 +44,13 @@ class Diagnostic uint32_t fillEmptyTOF(uint32_t frequency = 1) { return fill(1, frequency); } static ULong64_t getEmptyCrateKey(int crate); static ULong64_t getNoisyChannelKey(int channel); + static ULong64_t getDRMKey(int crate) { return 1000000 + crate * 1000; } + static ULong64_t getDRMerrorKey(int crate, int error) { return getDRMKey(crate) + error; } + uint32_t getFrequencyDRM(int crate) const { return getFrequency(getDRMKey(crate)); } + uint32_t getFrequencyDRMerror(int crate, int error) const { return getFrequency(getDRMerrorKey(crate, error)); } + uint32_t fillDRM(int crate, uint32_t frequency) { return fill(getDRMKey(crate), frequency); } + uint32_t fillDRMerror(int crate, int error, uint32_t frequency) { return fill(getDRMerrorKey(crate, error), frequency); } + static ULong64_t getTRMKey(int crate, int trm); void print(bool longFormat = false) const; void clear() { mVector.clear(); } diff --git a/DataFormats/Detectors/TOF/include/DataFormatsTOF/ParameterContainers.h b/DataFormats/Detectors/TOF/include/DataFormatsTOF/ParameterContainers.h index 9029c06d503c8..224906e43b8c6 100644 --- a/DataFormats/Detectors/TOF/include/DataFormatsTOF/ParameterContainers.h +++ b/DataFormats/Detectors/TOF/include/DataFormatsTOF/ParameterContainers.h @@ -18,10 +18,10 @@ #ifndef O2_TOF_PARAMCONTAINER_H #define O2_TOF_PARAMCONTAINER_H -#include "TNamed.h" -#include "TFile.h" -#include "Framework/Logger.h" -#include "map" +#include +#include +#include +#include namespace o2 { @@ -210,7 +210,13 @@ class ParameterCollection : public TNamed } /// @brief getter for the parameters stored in the container matching to a pass - const auto& getPars(const std::string& pass) const { return mParameters.at(pass); } + const std::unordered_map& getPars(const std::string& pass) const + { + if (!hasKey(pass)) { + LOG(fatal) << "Parameters for pass " << pass << " not found!"; + } + return mParameters.at(pass); + } /// @brief printing function for the content of the pass /// @param pass pass to print @@ -221,7 +227,7 @@ class ParameterCollection : public TNamed /// @brief Getter of the full map of parameters stored in the container /// @return returns the full map of parameters - const auto& getFullMap() { return mParameters; } + const std::unordered_map>& getFullMap() const { return mParameters; } /// Loader from file /// \param FileName name of the input file diff --git a/GPU/TPCFastTransformation/MultivariatePolynomial.cxx b/DataFormats/Detectors/TOF/src/DataFormatsParamTOFLinkDef.h similarity index 80% rename from GPU/TPCFastTransformation/MultivariatePolynomial.cxx rename to DataFormats/Detectors/TOF/src/DataFormatsParamTOFLinkDef.h index b1ffe616fb65e..2d6ee84bedb92 100644 --- a/GPU/TPCFastTransformation/MultivariatePolynomial.cxx +++ b/DataFormats/Detectors/TOF/src/DataFormatsParamTOFLinkDef.h @@ -9,7 +9,9 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file MultivariatePolynomial.cxx -/// \author Matthias Kleiner +#ifdef __CLING__ -#include "MultivariatePolynomial.h" +#pragma link C++ class o2::tof::Parameters < 5> + ; +#pragma link C++ class o2::tof::ParameterCollection + ; + +#endif diff --git a/DataFormats/Detectors/TOF/src/DataFormatsTOFLinkDef.h b/DataFormats/Detectors/TOF/src/DataFormatsTOFLinkDef.h index 55d1fd3973e70..03004e4c22afa 100644 --- a/DataFormats/Detectors/TOF/src/DataFormatsTOFLinkDef.h +++ b/DataFormats/Detectors/TOF/src/DataFormatsTOFLinkDef.h @@ -33,8 +33,6 @@ #pragma link C++ class std::vector < o2::dataformats::CalibInfoTOFshort> + ; #pragma link C++ class std::vector < o2::dataformats::CalibInfoTOF> + ; -#pragma link C++ class o2::tof::Parameters < 5> + ; -#pragma link C++ class o2::tof::ParameterCollection + ; #pragma link C++ class o2::tof::CTFHeader + ; #pragma link C++ class o2::tof::CompressedInfos + ; diff --git a/DataFormats/Detectors/TPC/CMakeLists.txt b/DataFormats/Detectors/TPC/CMakeLists.txt index 81b1d5efad59a..2cc69e16001a6 100644 --- a/DataFormats/Detectors/TPC/CMakeLists.txt +++ b/DataFormats/Detectors/TPC/CMakeLists.txt @@ -35,7 +35,8 @@ o2_add_library( O2::CommonDataFormat O2::Headers O2::DataSampling - O2::Algorithm) + O2::Algorithm + ROOT::Minuit) o2_target_root_dictionary( DataFormatsTPC diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/BetheBlochAleph.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/BetheBlochAleph.h index e8fe7457f3091..28b224298f36f 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/BetheBlochAleph.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/BetheBlochAleph.h @@ -12,27 +12,17 @@ #ifndef AliceO2_TPC_BETHEBLOCH_H_ #define AliceO2_TPC_BETHEBLOCH_H_ -#include "GPUCommonDef.h" -#include "GPUCommonMath.h" +#include "MathUtils/BetheBlochAleph.h" -namespace o2 -{ -namespace tpc +namespace o2::tpc { template GPUdi() T BetheBlochAleph(T bg, T kp1, T kp2, T kp3, T kp4, T kp5) { - T beta = bg / o2::gpu::GPUCommonMath::Sqrt(static_cast(1.) + bg * bg); - - T aa = o2::gpu::GPUCommonMath::Pow(beta, kp4); - T bb = o2::gpu::GPUCommonMath::Pow(static_cast(1.) / bg, kp5); - bb = o2::gpu::GPUCommonMath::Log(kp3 + bb); - - return (kp2 - aa - bb) * kp1 / aa; + return o2::common::BetheBlochAleph(bg, kp1, kp2, kp3, kp4, kp5); } -} // namespace tpc -} // namespace o2 +} // namespace o2::tpc #endif diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/CMV.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/CMV.h new file mode 100644 index 0000000000000..8195b3e39c689 --- /dev/null +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/CMV.h @@ -0,0 +1,124 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file CMV.h +/// @author Tuba Gündem, tuba.gundem@cern.ch +/// @brief Common mode values data format definition + +/// The data is sent by the CRU as 256+16 bit words. The CMV data layout is as follows: +/// - 256-bit Header: [version:8][packetID:8][errorCode:8][magicWord:8][heartbeatOrbit:32][heartbeatBC:16][padding:176] +/// - 16-bit CMV value: [sign:1][I8F7:15] where bit 15 is the sign (1=positive, 0=negative) and the lower 15 bits are a fixed point I8F7 value (8 integer bits, 7 fractional bits) +/// Float conversion: sign ? (value & 0x7FFF) / 128.0 : -(value & 0x7FFF) / 128.0 + +#ifndef ALICEO2_DATAFORMATSTPC_CMV_H +#define ALICEO2_DATAFORMATSTPC_CMV_H + +#include +#include + +namespace o2::tpc::cmv +{ + +static constexpr uint32_t NTimeBinsPerPacket = 3564; ///< number of time bins (covering 8 heartbeats) +static constexpr uint32_t NPacketsPerTFPerCRU = 4; ///< 4 packets per timeframe +static constexpr uint32_t NTimeBinsPerTF = NTimeBinsPerPacket * NPacketsPerTFPerCRU; ///< maximum number of timebins per timeframe (14256) + +/// Data padding: NTimeBinsPerPacket * sizeof(Data) = 3564 * 2 = 7128 bytes +static constexpr uint32_t DataSizeBytes = NTimeBinsPerPacket * sizeof(uint16_t); ///< 7128 bytes +static constexpr uint32_t DataPaddingBytes = (32 - (DataSizeBytes % 32)) % 32; ///< 8 bytes + +/// Header definition of the CMVs +struct Header { + static constexpr uint8_t MagicWord = 0xDC; + union { + uint64_t word0 = 0; ///< bits 0 - 63 + struct { + uint8_t version : 8; ///< version + uint8_t packetID : 8; ///< packet id + uint8_t errorCode : 8; ///< errors + uint8_t magicWord : 8; ///< magic word + uint32_t heartbeatOrbit : 32; ///< first heart beat timing of the package + }; + }; + union { + uint64_t word1 = 0; ///< bits 64 - 127 + struct { + uint16_t heartbeatBC : 16; ///< first BC id of the package + uint16_t unused1 : 16; ///< reserved + uint32_t unused2 : 32; ///< reserved + }; + }; + union { + uint64_t word3 = 0; ///< bits 128 - 191 + struct { + uint64_t unused3 : 64; ///< reserved + }; + }; + union { + uint64_t word4 = 0; ///< bits 192 - 255 + struct { + uint64_t unused4 : 64; ///< reserved + }; + }; +}; + +/// CMV single data container +struct Data { + uint16_t cmv{0}; ///< 16-bit signed fixed point value: bit 15 = sign (1=positive, 0=negative), bits 14-0 = I8F7 magnitude + + uint16_t getCMV() const { return cmv; } ///< raw 16-bit integer representation + void setCMV(uint16_t value) { cmv = value; } ///< set raw 16-bit integer representation + + // Decode to float: sign-magnitude with 7 fractional bits, range ±255.992 + float getCMVFloat() const + { + const bool positive = (cmv >> 15) & 1; // bit 15: sign (1=positive, 0=negative) + const float magnitude = (cmv & 0x7FFF) / 128.f; // lower 15 bits, shift right by 7 (divide by 2^7) + return positive ? magnitude : -magnitude; + } + + // Encode from float: truncates magnitude to 15 bits, range ±255.992 + void setCMVFloat(float value) + { + const bool positive = (value >= 0.f); + const uint16_t magnitude = static_cast( + std::lround(std::abs(value) * 128.f)) & + 0x7FFF; + cmv = (positive ? 0x8000 : 0x0000) | magnitude; + } +}; + +/// CMV full data container: one packet carries NTimeBinsPerPacket CMV values followed by padding +/// Layout: Header (32 bytes) + Data[NTimeBinsPerPacket] (7128 bytes) + padding (8 bytes) = 7168 bytes total (224 * 32 = 7168) +/// The padding bytes at the end of the data array are rubbish/unused and must not be interpreted as CMV values +struct Container { + Header header; ///< CMV data header + Data data[NTimeBinsPerPacket]; ///< data values + uint8_t padding[DataPaddingBytes]{}; ///< trailing padding to align data to 32-byte boundary + + // Header and data accessors + const Header& getHeader() const { return header; } + Header& getHeader() { return header; } + + const Data* getData() const { return data; } + Data* getData() { return data; } + + // Per timebin CMV accessors + uint16_t getCMV(uint32_t timeBin) const { return data[timeBin].getCMV(); } + void setCMV(uint32_t timeBin, uint16_t value) { data[timeBin].setCMV(value); } + + float getCMVFloat(uint32_t timeBin) const { return data[timeBin].getCMVFloat(); } + void setCMVFloat(uint32_t timeBin, float value) { data[timeBin].setCMVFloat(value); } +}; + +} // namespace o2::tpc::cmv + +#endif diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/CalibdEdxCorrection.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/CalibdEdxCorrection.h index 1d7b10dc965f7..f5088959edcf8 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/CalibdEdxCorrection.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/CalibdEdxCorrection.h @@ -42,14 +42,12 @@ class CalibdEdxCorrection static constexpr int FitSize = 288; ///< Number of fitted corrections static constexpr int ParamSize = 8; ///< Number of params per fit -#if !defined(GPUCA_ALIGPUCODE) +#if !defined(GPUCA_GPUCODE) CalibdEdxCorrection() { clear(); } CalibdEdxCorrection(std::string_view fileName) { loadFromFile(fileName); } -#else - CalibdEdxCorrection() = default; #endif ~CalibdEdxCorrection() = default; @@ -115,6 +113,9 @@ class CalibdEdxCorrection /// Single fit parameters averaged over all sectors for a stack type float getMeanEntries(const GEMstack stack, ChargeType charge) const; + /// set all corrections to 1, used for default initialization and to reset corrections + void setUnity(); + #endif private: diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/Constants.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/Constants.h index 6f6201b7de8df..0ddf7281be866 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/Constants.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/Constants.h @@ -28,7 +28,7 @@ namespace constants constexpr int MAXSECTOR = 36; // the number of global pad rows -#if defined(GPUCA_STANDALONE) && !defined(GPUCA_O2_LIB) && !defined(GPUCA_TPC_GEOMETRY_O2) +#if defined(GPUCA_STANDALONE) && defined(GPUCA_RUN2) constexpr int MAXGLOBALPADROW = 159; // Number of pad rows in Run 2, used for GPU TPC tests with Run 2 data #else constexpr int MAXGLOBALPADROW = 152; // Correct number of pad rows in Run 3 diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/DCS.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/DCS.h index 2f9f17f164872..d40b07c48e314 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/DCS.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/DCS.h @@ -30,9 +30,13 @@ #include "Framework/Logger.h" #include "DataFormatsTPC/Defs.h" +#include "MathUtils/fit.h" using namespace o2::tpc; +class TLinearFitter; +class TTree; + namespace o2::tpc::dcs { @@ -66,6 +70,19 @@ struct DataPointVector { uint32_t sensorNumber{}; std::vector data; + /// \brief convert data points to a vector of pairs: pair.first -> data and pair.second -> time + auto getPairOfVector() const + { + std::pair, std::vector> pairs; + pairs.first.reserve(data.size()); + pairs.second.reserve(data.size()); + for (const auto& dp : data) { + pairs.first.emplace_back(dp.value); + pairs.second.emplace_back(dp.time); + } + return pairs; + } + void fill(const TimeStampType time, const T& value) { data.emplace_back(DPType{time, value}); } void fill(const DPType& dataPoint) { data.emplace_back(dataPoint); } @@ -169,6 +186,45 @@ const T getAverageValueForTime(const std::vector>& dpVec return (nPoints > 0) ? ret / static_cast(nPoints) : T{}; } +template +dcs::TimeStampType getMinTime(const std::vector>& data, const bool roundToInterval, dcs::TimeStampType fitInterval) +{ + constexpr auto max = std::numeric_limits::max(); + dcs::TimeStampType firstTime = std::numeric_limits::max(); + for (const auto& sensor : data) { + const auto time = sensor.data.size() ? sensor.data.front().time : max; + firstTime = std::min(firstTime, time); + } + + // mFitInterval is is seconds. Round to full amount. + // if e.g. mFitInterval = 5min, then round 10:07:20.510 to 10:05:00.000 + if (roundToInterval) { + firstTime -= (firstTime % fitInterval); + } + + return firstTime; +} + +template +dcs::TimeStampType getMaxTime(const std::vector>& data) +{ + constexpr auto min = 0; + dcs::TimeStampType lastTime = 0; + for (const auto& sensor : data) { + const auto time = sensor.data.size() ? sensor.data.back().time : 0; + lastTime = std::max(lastTime, time); + } + + // mFitInterval is is seconds. Round to full amount. + // if e.g. mFitInterval = 5min, then round 10:07:20.510 to 10:05:00.000 + // TODO: fix this + // if (mRoundToInterval) { + // lastTime -= (lastTime % mFitInterval); + //} + + return lastTime; +} + using RawDPsF = DataPointVector; // using RawDPsI = DataPointVector; @@ -210,6 +266,12 @@ struct Temperature { static constexpr auto& getSensorPosition(const size_t sensor) { return SensorPosition[sensor]; } + /// \brief make fit of the mean temperature and gradients in time intervals + /// \param Side TPC side for which to make the fit + /// \param fitInterval time interval for the fits + /// \param roundToInterval round min time + void fitTemperature(Side side, dcs::TimeStampType fitInterval = 5 * 60 * 1000, const bool roundToInterval = false); + struct Stats { DataType mean{}; ///< average temperature in K DataType gradX{}; ///< horizontal temperature gradient in K/cm @@ -262,6 +324,9 @@ struct Temperature { doAppend(raw, other.raw); } + private: + bool makeFit(TLinearFitter& fitter, const int nDim, std::vector& xVals, std::vector& temperatures); + ClassDefNV(Temperature, 1); }; @@ -270,8 +335,7 @@ struct Temperature { /// struct HV { - HV() - noexcept; + HV() noexcept; // Exmple strings // TPC_HV_A03_I_G1B_I @@ -483,5 +547,77 @@ struct Gas { ClassDefNV(Gas, 1); }; +struct RobustPressure { + using Stats = o2::math_utils::RollingStats; + Stats surfaceAtmosPressure; ///< rolling statistics of surface sensor + Stats cavernAtmosPressure; ///< rolling statistics of cavern sensor 1 + Stats cavernAtmosPressure2; ///< rolling statistics of cavern sensor 2 + Stats cavernAtmosPressure12; ///< rolling statistics of cavernAtmosPressure/cavernAtmosPressure2 + Stats cavernAtmosPressure1S; ///< rolling statistics of cavernAtmosPressure/surfaceAtmosPressure + Stats cavernAtmosPressure2S; ///< rolling statistics of cavernAtmosPressure2/surfaceAtmosPressure + std::vector isOk; ///< bit mask of valid sensors: cavernBit 0, cavern2Bit = 1, surfaceBit = 2 + std::vector robustPressure; ///< combined robust pressure value that should be used + std::vector time; ///< time stamps of all pressure values + TimeStampType timeInterval; ///< time interval used for rolling statistics + TimeStampType timeIntervalRef; ///< reference time interval used for normalization of pressure sensors + float maxDist{}; ///< maximum allowed time distance between sensors to be accepted for robust pressure calculation + float maxDiff{0.2f}; ///< maximum allowed pressure difference between sensors to be accepted for robust pressure calculation + + ClassDefNV(RobustPressure, 2); +}; + +struct Pressure { + + /// \brief fill pressure data + /// \param sensor name of the sensor from DCS data stream + /// \param time measurement time + /// \param value pressure value + void fill(std::string_view sensor, const TimeStampType time, const DataType value); + + /// sort pressure values and remove obvious outliers + /// \param pMin min accepted pressure + /// \param pMax max accepted pressure + void sortAndClean(float pMin = 800, float pMax = 1100); + + /// \clear all stored data except the buffer + void clear(); + + /// append other pressure values + void append(const Pressure& other); + + /// \return get minimum time of stored data + TimeStampType getMinTime() const; + + /// \return get maximum time of stored data + TimeStampType getMaxTime() const; + + /// \brief average pressure values for given time interval + /// \param timeInterval time interval for which the pressure values are averaged + /// \param timeIntervalRef time interval used to calculate the normalization values for the pressure + /// \param tStart min time of the data + /// \param tEnd max time of the data + /// \param nthreads numbe rof threads used for some calculations + void makeRobustPressure(TimeStampType timeInterval = 100 * 1000, TimeStampType timeIntervalRef = 24 * 60 * 1000, TimeStampType tStart = 1, TimeStampType tEnd = 0, const int nthreads = 1); + + /// set aliases for the cuts used in the calculation of the robust pressure + static void setAliases(TTree* tree); + + RawDPsF cavernAtmosPressure{}; ///< raw pressure in the cavern from sensor 1 + RawDPsF cavernAtmosPressure2{}; ///< raw pressure in the cavern from sensor 2 + RawDPsF surfaceAtmosPressure{}; ///< raw pressure at the surface + RobustPressure robustPressure{}; ///< combined robust pressure estimator from all three sensors + + std::pair, std::vector> mCavernAtmosPressure1Buff{}; ///, std::vector> mCavernAtmosPressure2Buff{}; ///, std::vector> mSurfaceAtmosPressureBuff{}; ///, std::vector> mPressure12Buff{}; ///, std::vector> mPressure1SBuff{}; ///, std::vector> mPressure2SBuff{}; ///, std::vector> mRobPressureBuff{}; ///(static_cast(a) & static_cast(b)); } -inline PadFlags operator~(PadFlags a) { return static_cast(~static_cast(a)); } -inline PadFlags operator|(PadFlags a, PadFlags b) { return static_cast(static_cast(a) | static_cast(b)); } - // default point definitions for PointND, PointNDlocal, PointNDglobal are in // MathUtils/CartesianND.h diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/LtrCalibData.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/LtrCalibData.h index e410cd00dd3f6..e5e9b41229d50 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/LtrCalibData.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/LtrCalibData.h @@ -42,6 +42,7 @@ struct LtrCalibData { std::vector matchedLtrIDs; ///< matched laser track IDs std::vector nTrackTF; ///< number of laser tracks per TF std::vector dEdx; ///< dE/dx of each track + float tp{0.f}; ///< temperature over pressure ratio bool isValid() const { @@ -138,7 +139,7 @@ struct LtrCalibData { dEdx.clear(); } - ClassDefNV(LtrCalibData, 4); + ClassDefNV(LtrCalibData, 5); }; } // namespace o2::tpc diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/RawDataTypes.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/RawDataTypes.h index 26d3fe9cf21cc..db96280bde534 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/RawDataTypes.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/RawDataTypes.h @@ -28,6 +28,7 @@ enum Type : char { ZS = 2, ///< final Zero Suppression (can be ILBZS, DLBZS) IDC = 3, ///< Integrated Digitial Currents, with priority bit to end up in separate buffer SAC = 4, ///< Sampled Analogue Currents from the current monitor + CMV = 5, ///< Common mode values }; const std::unordered_map TypeNameMap{ @@ -36,6 +37,7 @@ const std::unordered_map TypeNameMap{ {Type::ZS, "ZS"}, {Type::IDC, "IDC"}, {Type::SAC, "SAC"}, + {Type::CMV, "CMV"}, }; } // namespace o2::tpc::raw_data_types diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/VDriftCorrFact.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/VDriftCorrFact.h index 03ad9755fedae..a20c37e9b2cee 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/VDriftCorrFact.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/VDriftCorrFact.h @@ -26,14 +26,15 @@ namespace o2::tpc { struct VDriftCorrFact { - long firstTime{}; ///< first time stamp of processed TFs - long lastTime{}; ///< last time stamp of processed TFs - long creationTime{}; ///< time of creation - float corrFact{1.0}; ///< drift velocity correction factor (multiplicative) - float corrFactErr{0.0}; ///< stat error of correction factor - float refVDrift{0.}; ///< reference vdrift for which factor was extracted + long firstTime{}; ///< first time stamp of processed TFs + long lastTime{}; ///< last time stamp of processed TFs + long creationTime{}; ///< time of creation + float corrFact{1.0}; ///< drift velocity correction factor (multiplicative) + float corrFactErr{0.0}; ///< stat error of correction factor + float refVDrift{0.}; ///< reference vdrift for which factor was extracted float refTimeOffset{0.}; ///< additive time offset reference (\mus) float timeOffsetCorr{0.}; ///< additive time offset correction (\mus) + float refTP{0.}; ///< reference temperature / pressure for which refVDrift was extracted float getVDrift() const { return refVDrift * corrFact; } float getVDriftError() const { return refVDrift * corrFactErr; } @@ -41,12 +42,19 @@ struct VDriftCorrFact { float getTimeOffset() const { return refTimeOffset + timeOffsetCorr; } // renormalize VDrift reference and correction either to provided new reference (if >0) or to correction 1 wrt current reference - void normalize(float newVRef = 0.f) + void normalize(float newVRef = 0.f, float tp = 0.f) { + float normVDrift = newVRef; if (newVRef == 0.f) { - newVRef = refVDrift * corrFact; + normVDrift = refVDrift * corrFact; + newVRef = normVDrift; + if ((tp > 0) && (refTP > 0)) { + // linear scaling based on relative change of T/P + normVDrift *= refTP / tp; + refTP = tp; // update reference T/P + } } - float fact = refVDrift / newVRef; + float fact = refVDrift / normVDrift; refVDrift = newVRef; corrFactErr *= fact; corrFact *= fact; @@ -66,7 +74,7 @@ struct VDriftCorrFact { } } - ClassDefNV(VDriftCorrFact, 2); + ClassDefNV(VDriftCorrFact, 3); }; } // namespace o2::tpc diff --git a/DataFormats/Detectors/TPC/src/CalibdEdxCorrection.cxx b/DataFormats/Detectors/TPC/src/CalibdEdxCorrection.cxx index 0991c8693d8e8..635b0e0817d6e 100644 --- a/DataFormats/Detectors/TPC/src/CalibdEdxCorrection.cxx +++ b/DataFormats/Detectors/TPC/src/CalibdEdxCorrection.cxx @@ -14,6 +14,7 @@ #include #include +#ifndef GPUCA_STANDALONE // o2 includes #include "Framework/Logger.h" #include "DataFormatsTPC/Defs.h" @@ -21,6 +22,7 @@ // root includes #include "TFile.h" +#endif using namespace o2::tpc; @@ -37,6 +39,8 @@ void CalibdEdxCorrection::clear() mDims = -1; } +#ifndef GPUCA_STANDALONE + void CalibdEdxCorrection::writeToFile(std::string_view fileName, std::string_view objName) const { std::unique_ptr file(TFile::Open(fileName.data(), "recreate")); @@ -168,3 +172,18 @@ float CalibdEdxCorrection::getMeanEntries(const GEMstack stack, ChargeType charg return mean / (SECTORSPERSIDE * SIDES); } + +void CalibdEdxCorrection::setUnity() +{ + for (int i = 0; i < FitSize; ++i) { + for (int j = 0; j < ParamSize; ++j) { + mParams[i][j] = 0.f; + } + mParams[i][0] = 1.f; // constant term = 1 + mChi2[i] = 0.f; + mEntries[i] = 0; + } + mDims = 0; +} + +#endif // GPUCA_STANDALONE diff --git a/DataFormats/Detectors/TPC/src/DCS.cxx b/DataFormats/Detectors/TPC/src/DCS.cxx index 131f6c9526647..b56d07acd7c73 100644 --- a/DataFormats/Detectors/TPC/src/DCS.cxx +++ b/DataFormats/Detectors/TPC/src/DCS.cxx @@ -16,6 +16,8 @@ #include #include "DataFormatsTPC/DCS.h" +#include "TLinearFitter.h" +#include "TTree.h" using namespace o2::tpc::dcs; @@ -117,3 +119,431 @@ TimeStampType Gas::getMaxTime() const return *std::max_element(times.begin(), times.end()); } + +TimeStampType Pressure::getMinTime() const +{ + constexpr auto max = std::numeric_limits::max(); + const std::vector times{ + cavernAtmosPressure.data.size() ? cavernAtmosPressure.data.front().time : max, + cavernAtmosPressure2.data.size() ? cavernAtmosPressure2.data.front().time : max, + surfaceAtmosPressure.data.size() ? surfaceAtmosPressure.data.front().time : max, + }; + + return *std::min_element(times.begin(), times.end()); +} + +TimeStampType Pressure::getMaxTime() const +{ + constexpr auto min = 0; + const std::vector times{ + cavernAtmosPressure.data.size() ? cavernAtmosPressure.data.back().time : min, + cavernAtmosPressure2.data.size() ? cavernAtmosPressure2.data.back().time : min, + surfaceAtmosPressure.data.size() ? surfaceAtmosPressure.data.back().time : min, + }; + + return *std::max_element(times.begin(), times.end()); +} + +bool Temperature::makeFit(TLinearFitter& fitter, const int nDim, std::vector& xVals, std::vector& temperatures) +{ + const int minPointsForFit = 5; + if (temperatures.empty() || (temperatures.size() < minPointsForFit)) { + LOGP(warning, "Number of points {} for fit smaller than minimum of {}!", temperatures.size(), minPointsForFit); + return false; + } + + fitter.ClearPoints(); + fitter.AssignData(temperatures.size(), nDim, xVals.data(), temperatures.data()); + int status = fitter.Eval(); + if (status == 1) { + LOGP(warning, "Fit failed!"); + return false; + } + return true; +} + +void Temperature::fitTemperature(Side side, dcs::TimeStampType fitInterval, const bool roundToInterval) +{ + // clear old data + auto& stats = (side == Side::A) ? statsA : statsC; + stats.clear(); + + // temperature fits in x-y + const int nDim = 2; + TLinearFitter fitter(nDim, "1 ++ x0 ++ x1", ""); + std::array startPos{}; + const size_t sensorOffset = (side == Side::C) ? dcs::Temperature::SensorsPerSide : 0; + + const dcs::TimeStampType refTime = getMinTime(raw, fitInterval, roundToInterval); + const dcs::TimeStampType refTimeMax = getMaxTime(raw); + + // calculate number of intervals and see if the last interval should be merged into the previous one + const int lastIntervalDuration = (refTimeMax - refTime) % fitInterval; + + // process the last interval only if it contains more than 50% of the interval duration + const bool procLastInt = (lastIntervalDuration / fitInterval > 0.5); + int numIntervals = (refTimeMax - refTime) / fitInterval + procLastInt; + if (numIntervals == 0) { + numIntervals = 1; + } + + // buffer for fit values + std::vector xVals; + std::vector temperatures; + xVals.reserve(2 * 1000); + temperatures.reserve(1000); + + for (int interval = 0; interval < numIntervals; ++interval) { + const dcs::TimeStampType timeStart = refTime + interval * fitInterval; + + // clear buffer + xVals.clear(); + temperatures.clear(); + + // TODO: check if we should use refTime + dcs::TimeStampType firstTime = std::numeric_limits::max(); + dcs::TimeStampType LastTime = 0; + + for (size_t iSensor = 0; iSensor < dcs::Temperature::SensorsPerSide; ++iSensor) { + const auto& sensor = raw[iSensor + sensorOffset]; + + LOGP(debug, "sensor {}, start {}, size {}", sensor.sensorNumber, startPos[iSensor], sensor.data.size()); + while (startPos[iSensor] < sensor.data.size()) { + const auto& dataPoint = sensor.data[startPos[iSensor]]; + if (((dataPoint.time - timeStart) >= fitInterval) && (interval != numIntervals - 1)) { + LOGP(debug, "sensor {}, {} - {} >= {}", sensor.sensorNumber, dataPoint.time, timeStart, fitInterval); + break; + } + firstTime = std::min(firstTime, dataPoint.time); + LastTime = std::max(LastTime, dataPoint.time); + const auto temperature = dataPoint.value; + // sanity check + ++startPos[iSensor]; + if (temperature < 15 || temperature > 25) { + continue; + } + const auto& pos = dcs::Temperature::SensorPosition[iSensor + sensorOffset]; + xVals.emplace_back(pos.x); + xVals.emplace_back(pos.y); + temperatures.emplace_back(temperature); + } + } + if (firstTime < std::numeric_limits::max() && !temperatures.empty()) { + const bool fitOk = makeFit(fitter, nDim, xVals, temperatures); + if (!fitOk) { + continue; + } + auto& stat = stats.data.emplace_back(); + stat.time = (firstTime + LastTime) / 2; + stat.value.mean = fitter.GetParameter(0); + stat.value.gradX = fitter.GetParameter(1); + stat.value.gradY = fitter.GetParameter(2); + + // check if data contains outliers + const float maxDeltaT = 1; + const float meanTemp = fitter.GetParameter(0); + const bool isDataGood = std::all_of(temperatures.begin(), temperatures.end(), [meanTemp, maxDeltaT](double t) { return std::abs(t - meanTemp) < maxDeltaT; }); + + // do second iteration only in case of outliers + if (!isDataGood) { + std::vector xVals2; + std::vector temperatures2; + xVals2.reserve(xVals.size()); + temperatures2.reserve(temperatures.size()); + for (int i = 0; i < temperatures.size(); ++i) { + if (std::abs(temperatures[i] - meanTemp) < maxDeltaT) { + const int idx = 2 * i; + xVals2.emplace_back(xVals[idx]); + xVals2.emplace_back(xVals[idx + 1]); + temperatures2.emplace_back(temperatures[i]); + } + } + const bool fitOk2 = makeFit(fitter, nDim, xVals2, temperatures2); + if (fitOk2) { + stat.value.mean = fitter.GetParameter(0); + stat.value.gradX = fitter.GetParameter(1); + stat.value.gradY = fitter.GetParameter(2); + } + } + } + } +} + +void Pressure::fill(std::string_view sensor, const TimeStampType time, const DataType value) +{ + if (sensor == "CavernAtmosPressure") { + cavernAtmosPressure.fill(time, value); + } else if (sensor == "CavernAtmosPressure2") { + cavernAtmosPressure2.fill(time, value); + } else if (sensor == "SurfaceAtmosPressure") { + surfaceAtmosPressure.fill(time, value); + } else { + LOGP(warning, "Unknown pressure sensor {}", sensor); + } +} + +void Pressure::sortAndClean(float pMin, float pMax) +{ + cavernAtmosPressure.sortAndClean(); + cavernAtmosPressure2.sortAndClean(); + surfaceAtmosPressure.sortAndClean(); + + auto removeOutliers = [](auto& dataVec, auto minVal, auto maxVal) { + dataVec.erase( + std::remove_if(dataVec.begin(), dataVec.end(), + [minVal, maxVal](const auto& dp) { + return (dp.value < minVal || dp.value > maxVal); + }), + dataVec.end()); + }; + + removeOutliers(cavernAtmosPressure.data, pMin, pMax); + removeOutliers(cavernAtmosPressure2.data, pMin, pMax); + removeOutliers(surfaceAtmosPressure.data, pMin, pMax); +} + +void Pressure::clear() +{ + cavernAtmosPressure.clear(); + cavernAtmosPressure2.clear(); + surfaceAtmosPressure.clear(); + robustPressure = RobustPressure(); +} + +void Pressure::append(const Pressure& other) +{ + cavernAtmosPressure.append(other.cavernAtmosPressure); + cavernAtmosPressure2.append(other.cavernAtmosPressure2); + surfaceAtmosPressure.append(other.surfaceAtmosPressure); +} + +void fillBuffer(std::pair, std::vector>& buffer, const std::pair, std::vector>& values, TimeStampType tStart, const int minPoints) +{ + const auto itStartBuff = std::lower_bound(buffer.second.begin(), buffer.second.end(), tStart); + size_t idxStartBuffer = std::distance(buffer.second.begin(), itStartBuff); + if (buffer.first.size() - idxStartBuffer < minPoints) { + if (buffer.first.size() < minPoints) { + idxStartBuffer = 0; + } else { + idxStartBuffer = buffer.first.size() - minPoints; + } + } + + std::pair, std::vector> buffTmp; + auto& [buffVals, buffTimes] = buffTmp; + + // Preallocate enough capacity to avoid reallocations + buffVals.reserve(buffer.first.size() - idxStartBuffer + values.first.size()); + buffTimes.reserve(buffer.second.size() - idxStartBuffer + values.second.size()); + // Insert the kept part of the old buffer + buffVals.insert(buffVals.end(), buffer.first.begin() + idxStartBuffer, buffer.first.end()); + buffTimes.insert(buffTimes.end(), buffer.second.begin() + idxStartBuffer, buffer.second.end()); + // Insert the new values + buffVals.insert(buffVals.end(), values.first.begin(), values.first.end()); + buffTimes.insert(buffTimes.end(), values.second.begin(), values.second.end()); + + // this should not happen + if (!std::is_sorted(buffTimes.begin(), buffTimes.end())) { + LOGP(info, "Pressure buffer not sorted after filling - sorting it"); + std::vector idx(buffTimes.size()); + o2::math_utils::SortData(buffTimes, idx); + o2::math_utils::Reorder(buffVals, idx); + o2::math_utils::Reorder(buffTimes, idx); + } + + buffer = std::move(buffTmp); +} + +void Pressure::makeRobustPressure(TimeStampType timeInterval, TimeStampType timeIntervalRef, TimeStampType tStart, TimeStampType tEnd, const int nthreads) +{ + const auto surfaceAtmosPressurePair = surfaceAtmosPressure.getPairOfVector(); + const auto cavernAtmosPressurePair = cavernAtmosPressure.getPairOfVector(); + const auto cavernAtmosPressure2Pair = cavernAtmosPressure2.getPairOfVector(); + + // round to second + tStart = tStart / 1000 * 1000; + const TimeStampType tStartRef = (tStart - timeIntervalRef); + const int minPointsRef = 50; + fillBuffer(mCavernAtmosPressure1Buff, cavernAtmosPressurePair, tStartRef, minPointsRef); + fillBuffer(mCavernAtmosPressure2Buff, cavernAtmosPressure2Pair, tStartRef, minPointsRef); + fillBuffer(mSurfaceAtmosPressureBuff, surfaceAtmosPressurePair, tStartRef, minPointsRef); + + int nIntervals = std::round((tEnd - tStart) / timeInterval); + if (nIntervals == 0) { + nIntervals = 1; // at least one interval + } + std::vector times; + times.reserve(nIntervals); + for (int i = 0; i < nIntervals; ++i) { + times.emplace_back(tStart + (i + 0.5) * timeInterval); + } + + /// minimum number of points in the interval - otherwise use the n closest points + const int minPoints = 4; + const auto cavernAtmosPressureStats = o2::math_utils::getRollingStatistics(mCavernAtmosPressure1Buff.second, mCavernAtmosPressure1Buff.first, times, timeInterval, nthreads, minPoints, minPoints); + const auto cavernAtmosPressure2Stats = o2::math_utils::getRollingStatistics(mCavernAtmosPressure2Buff.second, mCavernAtmosPressure2Buff.first, times, timeInterval, nthreads, minPoints, minPoints); + const auto surfaceAtmosPressureStats = o2::math_utils::getRollingStatistics(mSurfaceAtmosPressureBuff.second, mSurfaceAtmosPressureBuff.first, times, timeInterval, nthreads, minPoints, minPoints); + + // subtract the moving median values from the different sensors if they are ok + std::pair, std::vector> cavernAtmosPressure12; + std::pair, std::vector> cavernAtmosPressure1S; + std::pair, std::vector> cavernAtmosPressure2S; + cavernAtmosPressure12.first.reserve(nIntervals); + cavernAtmosPressure1S.first.reserve(nIntervals); + cavernAtmosPressure2S.first.reserve(nIntervals); + cavernAtmosPressure12.second.reserve(nIntervals); + cavernAtmosPressure1S.second.reserve(nIntervals); + cavernAtmosPressure2S.second.reserve(nIntervals); + + for (int i = 0; i < nIntervals; i++) { + // coarse check if data is close by + const int maxDist = 600 * 1000; + const bool cavernOk = (cavernAtmosPressureStats.median[i] > 0) && (cavernAtmosPressureStats.closestDistanceL[i] < maxDist) && (cavernAtmosPressureStats.closestDistanceR[i] < maxDist); + const bool cavern2Ok = (cavernAtmosPressure2Stats.median[i] > 0) && (cavernAtmosPressure2Stats.closestDistanceL[i] < maxDist) && (cavernAtmosPressure2Stats.closestDistanceR[i] < maxDist); + const bool surfaceOk = (surfaceAtmosPressureStats.median[i] > 0) && (surfaceAtmosPressureStats.closestDistanceL[i] < maxDist) && (surfaceAtmosPressureStats.closestDistanceR[i] < maxDist); + + if (cavernOk && cavern2Ok) { + cavernAtmosPressure12.first.emplace_back(cavernAtmosPressureStats.median[i] - cavernAtmosPressure2Stats.median[i]); + cavernAtmosPressure12.second.emplace_back(times[i]); + } + if (cavernOk && surfaceOk) { + cavernAtmosPressure1S.first.emplace_back(cavernAtmosPressureStats.median[i] - surfaceAtmosPressureStats.median[i]); + cavernAtmosPressure1S.second.emplace_back(times[i]); + } + if (cavern2Ok && surfaceOk) { + cavernAtmosPressure2S.first.emplace_back(cavernAtmosPressure2Stats.median[i] - surfaceAtmosPressureStats.median[i]); + cavernAtmosPressure2S.second.emplace_back(times[i]); + } + } + + fillBuffer(mPressure12Buff, cavernAtmosPressure12, tStartRef, minPointsRef); + fillBuffer(mPressure1SBuff, cavernAtmosPressure1S, tStartRef, minPointsRef); + fillBuffer(mPressure2SBuff, cavernAtmosPressure2S, tStartRef, minPointsRef); + + // get long term median of diffs - this is used for normalization of the pressure values - + const auto cavernAtmosPressure12Stats = o2::math_utils::getRollingStatistics(mPressure12Buff.second, mPressure12Buff.first, times, timeIntervalRef, nthreads, 3, minPointsRef); + const auto cavernAtmosPressure1SStats = o2::math_utils::getRollingStatistics(mPressure1SBuff.second, mPressure1SBuff.first, times, timeIntervalRef, nthreads, 3, minPointsRef); + const auto cavernAtmosPressure2SStats = o2::math_utils::getRollingStatistics(mPressure2SBuff.second, mPressure2SBuff.first, times, timeIntervalRef, nthreads, 3, minPointsRef); + + // calculate diffs of median values + const float maxDist = 20 * timeInterval; + const float maxDiff = 0.2; + std::pair, std::vector> robustPressureTmp; + robustPressureTmp.first.reserve(nIntervals); + robustPressureTmp.second.reserve(nIntervals); + std::vector isOk(nIntervals); + + for (int i = 0; i < nIntervals; ++i) { + // difference beween pressure values corrected for the long term median + const float delta12 = cavernAtmosPressureStats.median[i] - cavernAtmosPressure2Stats.median[i] - cavernAtmosPressure12Stats.median[i]; + const float delta1S = cavernAtmosPressureStats.median[i] - surfaceAtmosPressureStats.median[i] - cavernAtmosPressure1SStats.median[i]; + const float delta2S = cavernAtmosPressure2Stats.median[i] - surfaceAtmosPressureStats.median[i] - cavernAtmosPressure2SStats.median[i]; + + const auto distCavernAtmosPressureL = cavernAtmosPressureStats.closestDistanceL[i]; + const auto distCavernAtmosPressure2L = cavernAtmosPressure2Stats.closestDistanceL[i]; + const auto distSurfaceAtmosPressureL = surfaceAtmosPressureStats.closestDistanceL[i]; + const auto distCavernAtmosPressureR = cavernAtmosPressureStats.closestDistanceR[i]; + const auto distCavernAtmosPressure2R = cavernAtmosPressure2Stats.closestDistanceR[i]; + const auto distSurfaceAtmosPressureR = surfaceAtmosPressureStats.closestDistanceR[i]; + + // check if data is ok + const bool cavernDistOk = (cavernAtmosPressureStats.median[i] > 0) && ((distCavernAtmosPressureL < maxDist) || (distCavernAtmosPressureR < maxDist)); + const bool cavern2DistOk = (cavernAtmosPressure2Stats.median[i] > 0) && ((distCavernAtmosPressure2L < maxDist) || (distCavernAtmosPressure2R < maxDist)); + const bool surfaceDistOk = (surfaceAtmosPressureStats.median[i] > 0) && ((distSurfaceAtmosPressureL < maxDist) || (distSurfaceAtmosPressureR < maxDist)); + const bool onlyOneSensor = (cavernDistOk + cavern2DistOk + surfaceDistOk) == 1; // check if only 1 sensor exists, if so use that sensor + + uint8_t maskIsOkTmp = 0; + const int cavernBit = 0; // val 1 + const int cavern2Bit = 1; // val 2 + const int surfaceBit = 2; // val 4 + + // check if ratio sensor 1 and 2 are good + // maskIsOkTmp = 3 + if (((std::abs(delta12) < maxDiff) && (cavernDistOk && cavern2DistOk)) || onlyOneSensor) { + if (cavernDistOk) { + maskIsOkTmp |= (1 << cavernBit); + } + if (cavern2DistOk) { + maskIsOkTmp |= (1 << cavern2Bit); + } + } + + // check if ratio sensor 1 and surface are good + // maskIsOkTmp = 5 + if ((std::abs(delta1S) < maxDiff) && ((cavernDistOk && surfaceDistOk)) || onlyOneSensor) { + if (cavernDistOk) { + maskIsOkTmp |= (1 << cavernBit); + } + if (surfaceDistOk) { + maskIsOkTmp |= (1 << surfaceBit); + } + } + + // check if ratio sensor 2 and surface are good + // maskIsOkTmp = 6 + if ((std::abs(delta2S) < maxDiff) && ((cavern2DistOk && surfaceDistOk)) || onlyOneSensor) { + if (cavern2DistOk) { + maskIsOkTmp |= (1 << cavern2Bit); + } + if (surfaceDistOk) { + maskIsOkTmp |= (1 << surfaceBit); + } + } + + // calculate robust pressure + float pressure = 0; + int pressureCount = 0; + if ((maskIsOkTmp >> cavernBit) & 1) { + pressure += cavernAtmosPressureStats.median[i]; + pressureCount++; + } + + if ((maskIsOkTmp >> cavern2Bit) & 1) { + pressure += cavernAtmosPressure2Stats.median[i] + cavernAtmosPressure12Stats.median[i]; + pressureCount++; + } + + if ((maskIsOkTmp >> surfaceBit) & 1) { + pressure += surfaceAtmosPressureStats.median[i] + cavernAtmosPressure1SStats.median[i]; + pressureCount++; + } + + isOk[i] = maskIsOkTmp; + if (pressureCount > 0) { + pressure /= pressureCount; + robustPressureTmp.first.emplace_back(pressure); + robustPressureTmp.second.emplace_back(times[i]); + } + } + + fillBuffer(mRobPressureBuff, robustPressureTmp, tStartRef, minPointsRef); + + RobustPressure& pOut = robustPressure; + pOut.surfaceAtmosPressure = std::move(surfaceAtmosPressureStats); + pOut.cavernAtmosPressure2 = std::move(cavernAtmosPressure2Stats); + pOut.cavernAtmosPressure = std::move(cavernAtmosPressureStats); + pOut.cavernAtmosPressure12 = std::move(cavernAtmosPressure12Stats); + pOut.cavernAtmosPressure1S = std::move(cavernAtmosPressure1SStats); + pOut.cavernAtmosPressure2S = std::move(cavernAtmosPressure2SStats); + pOut.isOk = std::move(isOk); + pOut.robustPressure = o2::math_utils::getRollingStatistics(mRobPressureBuff.second, mRobPressureBuff.first, times, timeInterval, nthreads, 1, 5).median; + pOut.time = std::move(times); + pOut.timeInterval = timeInterval; + pOut.timeIntervalRef = timeIntervalRef; + pOut.maxDist = maxDist; + pOut.maxDiff = maxDiff; +} + +void Pressure::setAliases(TTree* tree) +{ + tree->SetAlias("cavernDistOk", "robustPressure.cavernAtmosPressure.median>0 && (robustPressure.cavernAtmosPressure.closestDistanceRSetAlias("cavern2DistOk", "robustPressure.cavernAtmosPressure2.median>0 && (robustPressure.cavernAtmosPressure2.closestDistanceRSetAlias("surfaceDistOk", "robustPressure.surfaceAtmosPressure.median>0 && (robustPressure.surfaceAtmosPressure.closestDistanceRSetAlias("onlyOneSensor", "(cavernDistOk + cavern2DistOk + surfaceDistOk) == 1"); + tree->SetAlias("delta12", "robustPressure.cavernAtmosPressure.median - robustPressure.cavernAtmosPressure2.median - robustPressure.cavernAtmosPressure12.median"); + tree->SetAlias("delta1S", "robustPressure.cavernAtmosPressure.median - robustPressure.surfaceAtmosPressure.median - robustPressure.cavernAtmosPressure1S.median"); + tree->SetAlias("delta2S", "robustPressure.surfaceAtmosPressure.median - robustPressure.cavernAtmosPressure2.median - robustPressure.cavernAtmosPressure2S.median"); + tree->SetAlias("delta12_Ok", "abs(delta12)SetAlias("delta1S_Ok", "abs(delta1S)SetAlias("delta2S_Ok", "abs(delta2S) + ; #pragma link C++ class o2::tpc::dcs::DataPointVector < o2::tpc::dcs::HV::StackState> + ; #pragma link C++ class o2::tpc::dcs::Gas + ; +#pragma link C++ class o2::tpc::dcs::Pressure + ; +#pragma link C++ class o2::tpc::dcs::RobustPressure + ; #pragma link C++ class o2::tpc::PIDResponse + ; #pragma link C++ class o2::tpc::TriggerWordDLBZS + ; #pragma link C++ class o2::tpc::TriggerInfoDLBZS + ; diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/CalGain.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/CalGain.h index f90101e7a4f21..97b3a73a86c03 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/CalGain.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/CalGain.h @@ -33,12 +33,52 @@ class CalGain void setMPVdEdx(int iDet, float mpv) { mMPVdEdx[iDet] = mpv; } - float getMPVdEdx(int iDet) const { return mMPVdEdx[iDet]; } + float getMPVdEdx(int iDet, bool defaultAvg = true) const + { + // if defaultAvg = false, we take the value stored whatever it is + // if defaultAvg = true and we have default value or bad value stored, we take the average on all chambers instead + if (!defaultAvg || isGoodGain(iDet)) + return mMPVdEdx[iDet]; + else { + if (std::fabs(mMeanGain + 999.) < 1e-6) + mMeanGain = getAverageGain(); + return mMeanGain; + } + } + + float getAverageGain() const + { + float averageGain = 0.; + int ngood = 0; + + for (int iDet = 0; iDet < constants::MAXCHAMBER; iDet++) { + if (isGoodGain(iDet)) { + // The chamber has correct calibration + ngood++; + averageGain += mMPVdEdx[iDet]; + } + } + if (ngood == 0) { + // we should make sure it never happens + return constants::MPVDEDXDEFAULT; + } + averageGain /= ngood; + return averageGain; + } + + bool isGoodGain(int iDet) const + { + if (std::fabs(mMPVdEdx[iDet] - constants::MPVDEDXDEFAULT) > 1e-6) + return true; + else + return false; + } private: std::array mMPVdEdx{}; ///< Most probable value of dEdx distribution per TRD chamber + mutable float mMeanGain{-999.}; ///! average gain, calculated only once - ClassDefNV(CalGain, 1); + ClassDefNV(CalGain, 2); }; } // namespace trd diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/CalVdriftExB.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/CalVdriftExB.h index bad9dcfef4e37..280f9d0d4b8a9 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/CalVdriftExB.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/CalVdriftExB.h @@ -34,14 +34,102 @@ class CalVdriftExB 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]; } + float getVdrift(int iDet, bool defaultAvg = true) const + { + // if defaultAvg = false, we take the value stored whatever it is + // if defaultAvg = true and we have default value or bad value stored, we take the average on all chambers instead + if (!defaultAvg || (isGoodExB(iDet) && isGoodVdrift(iDet))) + return mVdrift[iDet]; + else { + if (std::fabs(mMeanVdrift + 999.) < 1e-6) + mMeanVdrift = getAverageVdrift(); + return mMeanVdrift; + } + } + float getExB(int iDet, bool defaultAvg = true) const + { + if (!defaultAvg || (isGoodExB(iDet) && isGoodVdrift(iDet))) + return mExB[iDet]; + else { + if (std::fabs(mMeanExB + 999.) < 1e-6) + mMeanExB = getAverageExB(); + return mMeanExB; + } + } + + float getAverageVdrift() const + { + float averageVdrift = 0.; + int ngood = 0; + + for (int iDet = 0; iDet < constants::MAXCHAMBER; iDet++) { + if (isGoodExB(iDet) && isGoodVdrift(iDet)) { + // Both values need to be correct to declare a chamber as well calibrated + ngood++; + averageVdrift += mVdrift[iDet]; + } + } + if (ngood == 0) { + // we should make sure it never happens + return constants::VDRIFTDEFAULT; + } + averageVdrift /= ngood; + return averageVdrift; + } + + float getAverageExB() const + { + float averageExB = 0.; + int ngood = 0; + + for (int iDet = 0; iDet < constants::MAXCHAMBER; iDet++) { + if (isGoodExB(iDet) && isGoodVdrift(iDet)) { + // Both values need to be correct to declare a chamber as well calibrated + ngood++; + averageExB += mExB[iDet]; + } + } + if (ngood == 0) { + // we should make sure it never happens + return constants::EXBDEFAULT; + } + averageExB /= ngood; + return averageExB; + } + + bool isGoodExB(int iDet) const + { + // check if value is well calibrated or not + // default calibration if not enough entries + // close to boundaries indicate a failed fit + if (std::fabs(mExB[iDet] - constants::EXBDEFAULT) > 1e-6 && + std::fabs(mExB[iDet] - constants::EXBMIN) > 0.01 && + std::fabs(mExB[iDet] - constants::EXBMAX) > 0.01) + return true; + else + return false; + } + + bool isGoodVdrift(int iDet) const + { + // check if value is well calibrated or not + // default calibration if not enough entries + // close to boundaries indicate a failed fit + if (std::fabs(mVdrift[iDet] - constants::VDRIFTDEFAULT) > 1e-6 && + std::fabs(mVdrift[iDet] - constants::VDRIFTMIN) > 0.1 && + std::fabs(mVdrift[iDet] - constants::VDRIFTMAX) > 0.1) + return true; + else + return false; + } private: std::array mVdrift{}; ///< calibrated drift velocity per TRD chamber std::array mExB{}; ///< calibrated Lorentz angle per TRD chamber + mutable float mMeanVdrift{-999.}; ///! average drift velocity, calculated only once + mutable float mMeanExB{-999.}; ///! average lorentz angle, calculated only once - ClassDefNV(CalVdriftExB, 1); + ClassDefNV(CalVdriftExB, 2); }; } // namespace trd diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/Constants.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/Constants.h index 7a650cf3699cf..9a4da1024e251 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/Constants.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/Constants.h @@ -75,7 +75,11 @@ 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 constexpr double VDRIFTDEFAULT = 1.546; ///< default value for vDrift +constexpr double VDRIFTMIN = 0.4; ///< min value for vDrift +constexpr double VDRIFTMAX = 2.0; ///< max value for vDrift constexpr double EXBDEFAULT = 0.0; ///< default value for LorentzAngle +constexpr double EXBMIN = -0.4; ///< min value for LorentzAngle +constexpr double EXBMAX = 0.4; ///< max value for LorentzAngle constexpr int NBINSGAINCALIB = 320; ///< number of bins in the charge (Q0+Q1+Q2) histogram for gain calibration constexpr float MPVDEDXDEFAULT = 42.; ///< default Most Probable Value of TRD dEdx constexpr float T0DEFAULT = 1.2; ///< default value for t0 diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/Digit.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/Digit.h index 28ec6c76f4bef..9eba0318a5a13 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/Digit.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/Digit.h @@ -59,7 +59,7 @@ class Digit Digit(int det, int row, int pad, ArrayADC adc, int phase = 0); Digit(int det, int row, int pad); // add adc data and pretrigger phase in a separate step Digit(int det, int rob, int mcm, int channel, ArrayADC adc, int phase = 0); - Digit(int det, int rob, int mcm, int channel); // add adc data in a seperate step + Digit(int det, int rob, int mcm, int channel, int phase = 0); // add adc data // Copy Digit(const Digit&) = default; @@ -74,9 +74,11 @@ class Digit void setDetector(int det) { mDetector = ((mDetector & 0xf000) | (det & 0xfff)); } void setADC(ArrayADC const& adc) { mADC = adc; } void setADC(const gsl::span& adc) { std::copy(adc.begin(), adc.end(), mADC.begin()); } - void setPreTrigPhase(int phase) { mDetector = (((phase & 0xf) << 12) | (mDetector & 0xfff)); } + // set the trigger phase make sure it is mapped to 2 bits as it can only have 4 valid numbers shifted 0,3,6,9 or 1,4,7,10 etc. + void setPreTrigPhase(int phase); // Get methods int getDetector() const { return mDetector & 0xfff; } + int getDetectorInFull() const { return mDetector; } // return the entire mDetector 16 bits, so far only for CTF encoding. int getHCId() const { return (mDetector & 0xfff) * 2 + (mROB % 2); } int getPadRow() const { return HelperMethods::getPadRowFromMCM(mROB, mMCM); } int getPadCol() const { return HelperMethods::getPadColFromADC(mROB, mMCM, mChannel); } diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/PHData.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/PHData.h index b8873a5247d03..fc46ca0207993 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/PHData.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/PHData.h @@ -61,6 +61,66 @@ class PHData ClassDefNV(PHData, 1); }; + +/* + This data type is used to send around the information required to fill PH plots per chamber + + |19|18|17|16|15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00| + ------------------------------------------------------------- + |type |nNeighb | time bin | detector number | + ------------------------------------------------------------- +*/ +/* + This data type is used to send around the information required to fill PH plots per chamber + + |15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00| + ------------------------------------------------ + | ADC sum for all neigbours | + ------------------------------------------------ +*/ + +class PHDataHD +{ + public: + enum Origin : uint8_t { + ITSTPCTRD, + TPCTRD, + TRACKLET, + OTHER + }; + + PHDataHD() = default; + PHDataHD(int adc, int det, int tb, int nb, int type) { set(adc, det, tb, nb, type); } + + void set(int adc, int det, int tb, int nb, int type) + { + mDetector = det; + mTimeBin = tb; + mType = type; + mNNeighbours = nb; + mADC = adc; + } + + // the ADC sum for given time bin for up to three neighbours + int getADC() const { return mADC; } + // the TRD detector number + int getDetector() const { return mDetector; } + // the given time bin + int getTimebin() const { return mTimeBin; } + // number of neighbouring digits for which the ADC is accumulated + int getNNeighbours() const { return mNNeighbours; } + // the origin of this point: digit on ITS-TPC-TRD track, ... (see enum Origin above) + int getType() const { return mType; } + + private: + uint16_t mDetector{0}; + uint8_t mTimeBin{0}; + uint8_t mType{0}; + uint8_t mNNeighbours{0}; + uint16_t mADC{0}; + + ClassDefNV(PHDataHD, 1); +}; } // namespace o2::trd #endif // ALICEO2_TRD_PHDATA_H_ diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/RecoInputContainer.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RecoInputContainer.h index 353f635306e68..032dd4162a785 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/RecoInputContainer.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RecoInputContainer.h @@ -27,7 +27,7 @@ #include "Framework/InputRecord.h" #include "SimulationDataFormat/MCTruthContainer.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include #include diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/TrackTRD.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/TrackTRD.h index 9dcbde05fb743..b2182636d4591 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/TrackTRD.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/TrackTRD.h @@ -16,6 +16,7 @@ #define O2_DATAFORMATS_TRACK_TRD_H #include "GPUTRDTrack.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" namespace o2 { diff --git a/DataFormats/Detectors/TRD/src/DataFormatsTRDLinkDef.h b/DataFormats/Detectors/TRD/src/DataFormatsTRDLinkDef.h index 250a33b2c98e2..c6d36a7aee495 100644 --- a/DataFormats/Detectors/TRD/src/DataFormatsTRDLinkDef.h +++ b/DataFormats/Detectors/TRD/src/DataFormatsTRDLinkDef.h @@ -43,6 +43,7 @@ #pragma link C++ class o2::trd::ChannelInfo + ; #pragma link C++ class o2::trd::ChannelInfoContainer + ; #pragma link C++ struct o2::trd::PHData + ; +#pragma link C++ struct o2::trd::PHDataHD + ; #pragma link C++ class o2::trd::TRDDataCountersPerTimeFrame + ; #pragma link C++ class o2::trd::DataCountersPerTrigger + ; #pragma link C++ class std::vector < o2::trd::Tracklet64> + ; @@ -56,6 +57,7 @@ #pragma link C++ class std::vector < o2::trd::GainCalibHistos> + ; #pragma link C++ class std::vector < o2::trd::T0FitHistos> + ; #pragma link C++ class std::vector < o2::trd::PHData> + ; +#pragma link C++ class std::vector < o2::trd::PHDataHD> + ; #pragma link C++ class std::vector < o2::trd::KrCluster> + ; #pragma link C++ class std::vector < o2::trd::KrClusterTriggerRecord> + ; #pragma link C++ class std::vector < o2::trd::DataCountersPerTrigger> + ; diff --git a/DataFormats/Detectors/TRD/src/Digit.cxx b/DataFormats/Detectors/TRD/src/Digit.cxx index 9e94fe22068bb..37d6638ac0996 100644 --- a/DataFormats/Detectors/TRD/src/Digit.cxx +++ b/DataFormats/Detectors/TRD/src/Digit.cxx @@ -12,6 +12,7 @@ #include "DataFormatsTRD/Digit.h" #include #include +#include "fairlogger/Logger.h" namespace o2::trd { @@ -46,12 +47,18 @@ Digit::Digit(int det, int rob, int mcm, int channel, ArrayADC adc, int pretrigph setPreTrigPhase(pretrigphase); } -Digit::Digit(int det, int rob, int mcm, int channel) // add adc data in a seperate step +Digit::Digit(int det, int rob, int mcm, int channel, int pretrigphase) // add adc data in a seperate step { setDetector(det); setROB(rob); setMCM(mcm); setChannel(channel); + setPreTrigPhase(pretrigphase); +} + +void Digit::setPreTrigPhase(int phase) +{ + mDetector = ((((phase) & 0x3) << 12) | (mDetector & 0xfff)); } bool Digit::isSharedDigit() const diff --git a/DataFormats/Detectors/TRD/src/Tracklet64.cxx b/DataFormats/Detectors/TRD/src/Tracklet64.cxx index d7b63cae45354..0458dad92e678 100644 --- a/DataFormats/Detectors/TRD/src/Tracklet64.cxx +++ b/DataFormats/Detectors/TRD/src/Tracklet64.cxx @@ -25,7 +25,6 @@ void Tracklet64::print() const HelperMethods::getSector(getDetector()), HelperMethods::getStack(getDetector()), HelperMethods::getLayer(getDetector()), getROB(), getMCM(), getPadRow(), getPadCol(), getPosition(), getSlope(), getPID(), getQ0(), getQ1(), getQ2(), getFormat()); } -#ifndef GPUCA_GPUCODE_DEVICE void Tracklet64::printStream(std::ostream& stream) const { stream << "Tracklet64 : 0x" << std::hex << getTrackletWord(); @@ -50,7 +49,5 @@ bool operator<(const Tracklet64& lhs, const Tracklet64& rhs) (lhs.getDetector() == rhs.getDetector() && lhs.getROB() == rhs.getROB() && lhs.getMCM() == rhs.getMCM() && lhs.getPadRow() == rhs.getPadRow() && lhs.getPadCol() < rhs.getPadCol()); } -#endif // GPUCA_GPUCODE_DEVICE - } // namespace trd } // namespace o2 diff --git a/DataFormats/Detectors/Upgrades/ALICE3/CMakeLists.txt b/DataFormats/Detectors/Upgrades/ALICE3/CMakeLists.txt new file mode 100644 index 0000000000000..360b50d442d7d --- /dev/null +++ b/DataFormats/Detectors/Upgrades/ALICE3/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright 2019-2025 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +add_subdirectory(FD3) +add_subdirectory(TRK) diff --git a/DataFormats/Detectors/Upgrades/ALICE3/FD3/CMakeLists.txt b/DataFormats/Detectors/Upgrades/ALICE3/FD3/CMakeLists.txt new file mode 100644 index 0000000000000..e2219bb893612 --- /dev/null +++ b/DataFormats/Detectors/Upgrades/ALICE3/FD3/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(DataFormatsFD3 + SOURCES src/Hit.cxx + PUBLIC_LINK_LIBRARIES O2::FD3Base + O2::SimulationDataFormat + O2::CommonDataFormat + Microsoft.GSL::GSL + O2::DetectorsCommonDataFormats +) + +o2_target_root_dictionary(DataFormatsFD3 + HEADERS include/DataFormatsFD3/Hit.h +) diff --git a/DataFormats/Detectors/Upgrades/ALICE3/FD3/include/DataFormatsFD3/Hit.h b/DataFormats/Detectors/Upgrades/ALICE3/FD3/include/DataFormatsFD3/Hit.h new file mode 100644 index 0000000000000..4fde2f6cde6b4 --- /dev/null +++ b/DataFormats/Detectors/Upgrades/ALICE3/FD3/include/DataFormatsFD3/Hit.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 Hit.h +/// \brief Definition of the FD3 Hit class (based on ITSMFT and FV0) + +#ifndef ALICEO2_FVD_HIT_H_ +#define ALICEO2_FVD_HIT_H_ + +#include +#include "SimulationDataFormat/BaseHits.h" // for BasicXYZEHit +#include "Rtypes.h" // for Bool_t, Double_t, int, Double32_t, etc +#include "TVector3.h" // for TVector3 +#include "CommonUtils/ShmAllocator.h" + +namespace o2 +{ +namespace fd3 +{ + +class Hit : public o2::BasicXYZEHit +{ + public: + /// Default constructor + Hit() = default; + + /// Class Constructor + /// \param trackID Index of MCTrack + /// \param cellID Cell ID + /// \param startPos Coordinates at entrance to active volume [cm] + /// \param endPos Coordinates to active volume [cm] + /// \param startMom Momentum of track at entrance [GeV] + /// \param startE Energy of track at entrance [GeV] + /// \param endTime Final time [ns] + /// \param eLoss Energy deposit [GeV] + /// \param particlePdg PDG code of the partcile associated with the track + inline Hit(int trackID, + int cellID, + const math_utils::Point3D& startPos, + const math_utils::Point3D& endPos, + const math_utils::Vector3D& startMom, + double startE, + double endTime, + double eLoss, + int particlePdg); + + // Entrance position getters + math_utils::Point3D const& GetPosStart() const { return mPositionStart; } + float GetStartX() const { return mPositionStart.X(); } + float GetStartY() const { return mPositionStart.Y(); } + float GetStartZ() const { return mPositionStart.Z(); } + template + void GetStartPosition(F& x, F& y, F& z) const + { + x = GetStartX(); + y = GetStartY(); + z = GetStartZ(); + } + + // Momentum getters + math_utils::Vector3D const& GetMomentum() const { return mMomentumStart; } + math_utils::Vector3D& GetMomentum() { return mMomentumStart; } + float GetPx() const { return mMomentumStart.X(); } + float GetPy() const { return mMomentumStart.Y(); } + float GetPz() const { return mMomentumStart.Z(); } + float GetE() const { return mEnergyStart; } + float GetTotalEnergyAtEntrance() const { return GetE(); } + int GetParticlePdg() const { return mParticlePdg; } + + void Print(const Option_t* opt) const; + + private: + math_utils::Vector3D mMomentumStart; ///< momentum at entrance + math_utils::Point3D mPositionStart; ///< position at entrance (base mPos give position on exit) + float mEnergyStart; ///< total energy at entrance + int mParticlePdg; ///< PDG code of the particle associated with this track + + ClassDefNV(Hit, 1); +}; + +Hit::Hit(int trackID, + int detID, + const math_utils::Point3D& startPos, + const math_utils::Point3D& endPos, + const math_utils::Vector3D& startMom, + double startE, + double endTime, + double eLoss, + int particlePdg) + : BasicXYZEHit(endPos.X(), + endPos.Y(), + endPos.Z(), + endTime, + eLoss, + trackID, + detID), + mMomentumStart(startMom.X(), startMom.Y(), startMom.Z()), + mPositionStart(startPos.X(), startPos.Y(), startPos.Z()), + mEnergyStart(startE), + mParticlePdg(particlePdg) +{ +} + +} // namespace fd3 +} // namespace o2 + +#ifdef USESHM +namespace std +{ +template <> +class allocator : public o2::utils::ShmAllocator +{ +}; + +} // namespace std +#endif /* USESHM */ +#endif /* ALICEO2_FD3_HIT_H_ */ diff --git a/Detectors/FIT/FT0/workflow/src/FT0DataReaderDPLSpec.cxx b/DataFormats/Detectors/Upgrades/ALICE3/FD3/src/DataFormatsFD3LinkDef.h similarity index 72% rename from Detectors/FIT/FT0/workflow/src/FT0DataReaderDPLSpec.cxx rename to DataFormats/Detectors/Upgrades/ALICE3/FD3/src/DataFormatsFD3LinkDef.h index caa642794b561..1014b3d8c704e 100644 --- a/Detectors/FIT/FT0/workflow/src/FT0DataReaderDPLSpec.cxx +++ b/DataFormats/Detectors/Upgrades/ALICE3/FD3/src/DataFormatsFD3LinkDef.h @@ -9,16 +9,13 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// @file FT0DataReaderDPLSpec.cxx +#ifdef __CLING__ -#include "FT0Workflow/FT0DataReaderDPLSpec.h" +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; -using namespace o2::framework; +#pragma link C++ class o2::fd3::Hit + ; +#pragma link C++ class vector < o2::fd3::Hit> + ; -namespace o2 -{ -namespace ft0 -{ - -} // namespace ft0 -} // namespace o2 +#endif diff --git a/Detectors/Vertexing/src/FwdDCAFitterN.cxx b/DataFormats/Detectors/Upgrades/ALICE3/FD3/src/Hit.cxx similarity index 54% rename from Detectors/Vertexing/src/FwdDCAFitterN.cxx rename to DataFormats/Detectors/Upgrades/ALICE3/FD3/src/Hit.cxx index f7176aa5039fd..403a3402bd30c 100644 --- a/Detectors/Vertexing/src/FwdDCAFitterN.cxx +++ b/DataFormats/Detectors/Upgrades/ALICE3/FD3/src/Hit.cxx @@ -9,25 +9,27 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file DCAFitterN.cxx -/// \brief Defintions for N-prongs secondary vertex fit -/// \author ruben.shahoyan@cern.ch, adapted from central barrel to fwd rapidities by Rita Sadek, rita.sadek@cern.ch +/// \file Hit.cxx +/// \brief Implementation of the Hit class -#include "DetectorsVertexing/FwdDCAFitterN.h" +#include "DataFormatsFD3/Hit.h" +#include + +ClassImp(o2::fd3::Hit); namespace o2 { -namespace vertexing +namespace fd3 { -void __test_instance__() +void Hit::Print(const Option_t* opt) const { - FwdDCAFitter2 ft2; - FwdDCAFitter3 ft3; - o2::track::TrackParCovFwd tr; - ft2.process(tr, tr); - ft3.process(tr, tr, tr); + 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 vertexing +} // namespace fd3 } // namespace o2 diff --git a/DataFormats/Detectors/Upgrades/ALICE3/TRK/CMakeLists.txt b/DataFormats/Detectors/Upgrades/ALICE3/TRK/CMakeLists.txt new file mode 100644 index 0000000000000..c239a2a36845d --- /dev/null +++ b/DataFormats/Detectors/Upgrades/ALICE3/TRK/CMakeLists.txt @@ -0,0 +1,24 @@ +# Copyright 2019-2026 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does 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(DataFormatsTRK + SOURCES src/Cluster.cxx + src/ROFRecord.cxx + PUBLIC_LINK_LIBRARIES O2::CommonDataFormat + O2::DataFormatsITSMFT + O2::SimulationDataFormat +) + +o2_target_root_dictionary(DataFormatsTRK + HEADERS include/DataFormatsTRK/Cluster.h + include/DataFormatsTRK/ROFRecord.h + LINKDEF src/DataFormatsTRKLinkDef.h +) diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0Workflow.h b/DataFormats/Detectors/Upgrades/ALICE3/TRK/include/DataFormatsTRK/Cluster.h similarity index 50% rename from Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0Workflow.h rename to DataFormats/Detectors/Upgrades/ALICE3/TRK/include/DataFormatsTRK/Cluster.h index a4988b2c18fc7..ec68191b3c43f 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0Workflow.h +++ b/DataFormats/Detectors/Upgrades/ALICE3/TRK/include/DataFormatsTRK/Cluster.h @@ -1,4 +1,4 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. // See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. // All rights not expressly granted are reserved. // @@ -9,20 +9,30 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef O2_FIT_FT0WORKFLOW_H -#define O2_FIT_FT0WORKFLOW_H +#ifndef ALICEO2_DATAFORMATSTRK_CLUSTER_H +#define ALICEO2_DATAFORMATSTRK_CLUSTER_H -/// @file FT0Workflow.h +#include +#include +#include -#include "Framework/WorkflowSpec.h" - -namespace o2 -{ -namespace ft0 +namespace o2::trk { -framework::WorkflowSpec getFT0Workflow(bool isExtendedMode, bool useProcess, - bool dumpProcessor, bool dumpReader, - bool disableRootOut, bool askSTFDist); -} // namespace ft0 -} // namespace o2 + +struct Cluster { + uint16_t chipID = 0; + uint16_t row = 0; + uint16_t col = 0; + uint16_t size = 1; + int16_t subDetID = -1; + int16_t layer = -1; + int16_t disk = -1; + + std::string asString() const; + + ClassDefNV(Cluster, 1); +}; + +} // namespace o2::trk + #endif diff --git a/DataFormats/Detectors/Upgrades/ALICE3/TRK/include/DataFormatsTRK/ROFRecord.h b/DataFormats/Detectors/Upgrades/ALICE3/TRK/include/DataFormatsTRK/ROFRecord.h new file mode 100644 index 0000000000000..86ee31389fd5f --- /dev/null +++ b/DataFormats/Detectors/Upgrades/ALICE3/TRK/include/DataFormatsTRK/ROFRecord.h @@ -0,0 +1,75 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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_DATAFORMATSTRK_ROFRECORD_H +#define ALICEO2_DATAFORMATSTRK_ROFRECORD_H + +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonDataFormat/RangeReference.h" +#include +#include +#include + +namespace o2::trk +{ + +class ROFRecord +{ + public: + using EvIdx = o2::dataformats::RangeReference; + using BCData = o2::InteractionRecord; + using ROFtype = unsigned int; + + ROFRecord() = default; + ROFRecord(const BCData& bc, ROFtype rof, int idx, int n) + : mBCData(bc), mROFEntry(idx, n), mROFrame(rof) {} + + void setBCData(const BCData& bc) { mBCData = bc; } + void setROFrame(ROFtype rof) { mROFrame = rof; } + void setEntry(EvIdx entry) { mROFEntry = entry; } + void setFirstEntry(int idx) { mROFEntry.setFirstEntry(idx); } + void setNEntries(int n) { mROFEntry.setEntries(n); } + + const BCData& getBCData() const { return mBCData; } + BCData& getBCData() { return mBCData; } + EvIdx getEntry() const { return mROFEntry; } + EvIdx& getEntry() { return mROFEntry; } + int getNEntries() const { return mROFEntry.getEntries(); } + int getFirstEntry() const { return mROFEntry.getFirstEntry(); } + ROFtype getROFrame() const { return mROFrame; } + + std::string asString() const; + + private: + o2::InteractionRecord mBCData; + EvIdx mROFEntry; + ROFtype mROFrame = 0; + + ClassDefNV(ROFRecord, 1); +}; + +struct MC2ROFRecord { + using ROFtype = unsigned int; + + int eventRecordID = -1; + int rofRecordID = 0; + ROFtype minROF = 0; + ROFtype maxROF = 0; + + MC2ROFRecord() = default; + MC2ROFRecord(int evID, int rofRecID, ROFtype mnrof, ROFtype mxrof) : eventRecordID(evID), rofRecordID(rofRecID), minROF(mnrof), maxROF(mxrof) {} + + ClassDefNV(MC2ROFRecord, 1); +}; + +} // namespace o2::trk + +#endif diff --git a/DataFormats/Detectors/Upgrades/ALICE3/TRK/src/Cluster.cxx b/DataFormats/Detectors/Upgrades/ALICE3/TRK/src/Cluster.cxx new file mode 100644 index 0000000000000..6c96692ea5a9e --- /dev/null +++ b/DataFormats/Detectors/Upgrades/ALICE3/TRK/src/Cluster.cxx @@ -0,0 +1,28 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsTRK/Cluster.h" +#include + +ClassImp(o2::trk::Cluster); + +namespace o2::trk +{ + +std::string Cluster::asString() const +{ + std::ostringstream stream; + stream << "chip=" << chipID << " row=" << row << " col=" << col << " size=" << size + << " subDet=" << subDetID << " layer=" << layer << " disk=" << disk; + return stream.str(); +} + +} // namespace o2::trk diff --git a/DataFormats/Detectors/Upgrades/ALICE3/TRK/src/DataFormatsTRKLinkDef.h b/DataFormats/Detectors/Upgrades/ALICE3/TRK/src/DataFormatsTRKLinkDef.h new file mode 100644 index 0000000000000..36528d9dd2c46 --- /dev/null +++ b/DataFormats/Detectors/Upgrades/ALICE3/TRK/src/DataFormatsTRKLinkDef.h @@ -0,0 +1,25 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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::Cluster + ; +#pragma link C++ class std::vector < o2::trk::Cluster> + ; +#pragma link C++ class o2::trk::ROFRecord + ; +#pragma link C++ class std::vector < o2::trk::ROFRecord> + ; +#pragma link C++ class o2::trk::MC2ROFRecord + ; +#pragma link C++ class std::vector < o2::trk::MC2ROFRecord> + ; + +#endif diff --git a/DataFormats/Detectors/Upgrades/ALICE3/TRK/src/ROFRecord.cxx b/DataFormats/Detectors/Upgrades/ALICE3/TRK/src/ROFRecord.cxx new file mode 100644 index 0000000000000..79745f9854eb7 --- /dev/null +++ b/DataFormats/Detectors/Upgrades/ALICE3/TRK/src/ROFRecord.cxx @@ -0,0 +1,29 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "DataFormatsTRK/ROFRecord.h" +#include + +ClassImp(o2::trk::ROFRecord); +ClassImp(o2::trk::MC2ROFRecord); + +namespace o2::trk +{ + +std::string ROFRecord::asString() const +{ + std::ostringstream stream; + stream << "IR=" << mBCData.asString() << " ROFrame=" << mROFrame + << " first=" << mROFEntry.getFirstEntry() << " n=" << mROFEntry.getEntries(); + return stream.str(); +} + +} // namespace o2::trk diff --git a/DataFormats/Detectors/Upgrades/CMakeLists.txt b/DataFormats/Detectors/Upgrades/CMakeLists.txt index a2d470b8ff6d5..0dfe07dc2827d 100644 --- a/DataFormats/Detectors/Upgrades/CMakeLists.txt +++ b/DataFormats/Detectors/Upgrades/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# Copyright 2019-2025 CERN and copyright holders of ALICE O2. # See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. # All rights not expressly granted are reserved. # @@ -10,3 +10,4 @@ # or submit itself to any jurisdiction. message(STATUS "Building dataformats for upgrades") +add_subdirectory(ALICE3) diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/FEEConfig.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/FEEConfig.h deleted file mode 100644 index b084507b84519..0000000000000 --- a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/FEEConfig.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -// 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 index 6e0b99dca6761..3ce90a95f7248 100644 --- a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/Hit.h +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/Hit.h @@ -58,6 +58,7 @@ class Hit : public o2::BasicXYZEHit float getPMCLightYield() const { return mNphePMC; } float getPMQLightYield() const { return mNphePMQ; } int getNumContributingSteps() const { return mNoContributingSteps; } + bool getSecFlag() const { return mSecFlag; } private: Int_t mParentID; diff --git a/DataFormats/Headers/include/Headers/DataHeader.h b/DataFormats/Headers/include/Headers/DataHeader.h index 2dbfbd67d8d6c..dbcdb8e0bba89 100644 --- a/DataFormats/Headers/include/Headers/DataHeader.h +++ b/DataFormats/Headers/include/Headers/DataHeader.h @@ -588,6 +588,7 @@ constexpr o2::header::DataOrigin gDataOriginTF3{"TF3"}; constexpr o2::header::DataOrigin gDataOriginRCH{"RCH"}; constexpr o2::header::DataOrigin gDataOriginMI3{"MI3"}; constexpr o2::header::DataOrigin gDataOriginECL{"ECL"}; // upgrades +constexpr o2::header::DataOrigin gDataOriginFD3{"FD3"}; // upgrades constexpr o2::header::DataOrigin gDataOriginGPU{"GPU"}; @@ -599,6 +600,7 @@ constexpr o2::header::DataDescription gDataDescriptionClusters{"CLUSTERS"}; constexpr o2::header::DataDescription gDataDescriptionTracks{"TRACKS"}; constexpr o2::header::DataDescription gDataDescriptionConfig{"CONFIGURATION"}; constexpr o2::header::DataDescription gDataDescriptionInfo{"INFORMATION"}; +constexpr o2::header::DataDescription gDataDescriptionEos{"EOS"}; constexpr o2::header::DataDescription gDataDescriptionROOTStreamers{"ROOT STREAMERS"}; constexpr o2::header::DataDescription gDataDescriptionDISTSTF{"DISTSUBTIMEFRAME"}; /// @} // end of doxygen group diff --git a/DataFormats/Headers/include/Headers/DataHeaderHelpers.h b/DataFormats/Headers/include/Headers/DataHeaderHelpers.h index aa93414cfb99f..4f7e49acb4d98 100644 --- a/DataFormats/Headers/include/Headers/DataHeaderHelpers.h +++ b/DataFormats/Headers/include/Headers/DataHeaderHelpers.h @@ -79,7 +79,8 @@ struct fmt::formatter { 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); + fmt::format(" runNumber : {}\n", h.runNumber) + + fmt::format(" split : {}/{}\n", h.splitPayloadIndex, h.splitPayloadParts); return fmt::format_to(ctx.out(), "{}", res); } else { auto res = fmt::format("{}/{}/{}", diff --git a/DataFormats/Headers/include/Headers/Stack.h b/DataFormats/Headers/include/Headers/Stack.h index 259a445f18cf8..9770df9fa54ef 100644 --- a/DataFormats/Headers/include/Headers/Stack.h +++ b/DataFormats/Headers/include/Headers/Stack.h @@ -14,10 +14,7 @@ #include "MemoryResources/MemoryResources.h" #include "Headers/DataHeader.h" -namespace o2 -{ - -namespace header +namespace o2::header { //__________________________________________________________________________________________________ /// @struct Stack @@ -39,26 +36,27 @@ struct Stack { private: struct freeobj { - freeobj(memory_resource* mr) : resource(mr) {} + freeobj(memory_resource* mr, size_t s) : resource(mr), size(s) {} memory_resource* resource{nullptr}; - void operator()(std::byte* ptr) { resource->deallocate(ptr, 0, 0); } + size_t size{0}; + void operator()(std::byte* ptr) { resource->deallocate(ptr, size, alignof(std::max_align_t)); } }; public: - using allocator_type = boost::container::pmr::polymorphic_allocator; + using allocator_type = fair::mq::pmr::polymorphic_allocator; using value_type = std::byte; - using BufferType = std::unique_ptr; //this gives us proper default move semantics for free + using BufferType = std::unique_ptr; // this gives us proper default move semantics for free Stack() = default; Stack(Stack&&) = default; Stack(Stack&) = delete; Stack& operator=(Stack&) = delete; - Stack& operator=(Stack&&) = default; + Stack& operator=(Stack&&) = delete; - value_type* data() const { return buffer.get(); } - size_t size() const { return bufferSize; } + [[nodiscard]] value_type* data() const { return buffer.get(); } + [[nodiscard]] size_t size() const { return bufferSize; } allocator_type get_allocator() const { return allocator; } - const BaseHeader* first() const { return reinterpret_cast(this->data()); } + [[nodiscard]] const BaseHeader* first() const { return reinterpret_cast(this->data()); } static const BaseHeader* firstHeader(std::byte const* buf) { return BaseHeader::get(buf); } static const BaseHeader* lastHeader(std::byte const* buf) { @@ -90,9 +88,9 @@ struct Stack { /// all headers must derive from BaseHeader, in addition also other stacks can be passed to ctor. template >::value, int> = 0> + !std::is_convertible>::value, int> = 0> Stack(FirstArgType&& firstHeader, Headers&&... headers) - : Stack(boost::container::pmr::new_delete_resource(), std::forward(firstHeader), + : Stack(fair::mq::pmr::new_delete_resource(), std::forward(firstHeader), std::forward(headers)...) { } @@ -102,7 +100,7 @@ struct Stack { Stack(const allocator_type allocatorArg, Headers&&... headers) : allocator{allocatorArg}, bufferSize{calculateSize(std::forward(headers)...)}, - buffer{static_cast(allocator.resource()->allocate(bufferSize, alignof(std::max_align_t))), freeobj{allocator.resource()}} + buffer{static_cast(allocator.resource()->allocate(bufferSize, alignof(std::max_align_t))), freeobj{allocator.resource(), bufferSize}} { if constexpr (sizeof...(headers) > 1) { injectAll(buffer.get(), std::forward(headers)...); @@ -122,7 +120,7 @@ struct Stack { template constexpr static size_t calculateSize(T&& h) noexcept { - //if it's a pointer (to a stack) traverse it + // if it's a pointer (to a stack) traverse it if constexpr (std::is_convertible_v) { const BaseHeader* next = BaseHeader::get(std::forward(h)); if (!next) { @@ -133,19 +131,19 @@ struct Stack { size += next->size(); } return size; - //otherwise get the size directly + // otherwise get the size directly } else { return h.size(); } } - //recursion terminator + // recursion terminator constexpr static size_t calculateSize() { return 0; } private: - allocator_type allocator{boost::container::pmr::new_delete_resource()}; + allocator_type allocator{fair::mq::pmr::new_delete_resource()}; size_t bufferSize{0}; - BufferType buffer{nullptr, freeobj{allocator.resource()}}; + BufferType buffer{nullptr, freeobj{allocator.resource(), 0}}; //______________________________________________________________________________________________ template @@ -231,7 +229,6 @@ struct Stack { } }; -} // namespace header -} // namespace o2 +} // namespace o2::header #endif // HEADERS_STACK_H diff --git a/DataFormats/Headers/include/Headers/SubframeMetadata.h b/DataFormats/Headers/include/Headers/SubframeMetadata.h deleted file mode 100644 index 255fa0ceb8db6..0000000000000 --- a/DataFormats/Headers/include/Headers/SubframeMetadata.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef SUBFRAMEMETADATA_H -#define SUBFRAMEMETADATA_H - -#include - -namespace o2 -{ -namespace data_flow -{ - -struct SubframeMetadata { - // TODO: replace with timestamp struct - // IDEA: not timeframeID because can be calculcated with helper function - // QUESTION: isn't the duration set to ~22ms? - uint64_t startTime = ~(uint64_t)0; - uint64_t duration = ~(uint64_t)0; - - //further meta data to be added - - // putting data specific to FLP origin - int flpIndex; -}; - -// Helper function to derive the timeframe id from the actual timestamp. -// Timestamp is in nanoseconds. Each Timeframe is ~22ms i.e. 2^17 nanoseconds, -// so we can get a unique id by dividing by the timeframe period and masking -// the lower 16 bits. Overlaps will only happen every ~ 22 minutes. -constexpr uint16_t - timeframeIdFromTimestamp(uint64_t timestamp, uint64_t timeFrameDuration) -{ - return (timestamp / timeFrameDuration) & 0xffff; -} - -// A Mockup class to describe some TPC-like payload -struct TPCTestCluster { - float x = 0.f; - float y = 0.f; - float z = 1.5f; - float q = 0.; - uint64_t timeStamp; // the time this thing was digitized/recorded -}; - -struct TPCTestPayload { - std::vector clusters; -}; - -// a mockup class to describe some "ITS" payload -struct ITSRawData { - float x = -1.; - float y = 1.; - uint64_t timeStamp; -}; - -} // namespace data_flow -} // namespace o2 - -#endif diff --git a/DataFormats/Headers/test/testDataHeader.cxx b/DataFormats/Headers/test/testDataHeader.cxx index 0703fc6c3ae71..2403c1a6230be 100644 --- a/DataFormats/Headers/test/testDataHeader.cxx +++ b/DataFormats/Headers/test/testDataHeader.cxx @@ -280,8 +280,8 @@ BOOST_AUTO_TEST_CASE(headerStack_test) Stack s2{s1, meta}; BOOST_CHECK(s2.size() == s1.size() + sizeof(decltype(meta))); - //check dynamic construction - where we don't have the type information and need to - //work with BaseHeader pointers + // check dynamic construction - where we don't have the type information and need to + // work with BaseHeader pointers const test::MetaHeader thead{2}; o2::header::BaseHeader const* bname = reinterpret_cast(&thead); Stack ds2(s1, *bname); @@ -313,8 +313,8 @@ BOOST_AUTO_TEST_CASE(headerStack_test) BOOST_REQUIRE(h3 != nullptr); BOOST_CHECK(h3->secret == 42); - //test constructing from a buffer and an additional header - using namespace boost::container::pmr; + // test constructing from a buffer and an additional header + using namespace fair::mq::pmr; Stack s5(new_delete_resource(), s1.data(), Stack{}, meta); BOOST_CHECK(s5.size() == s1.size() + sizeof(meta)); // check if we can find the header even though there was an empty stack in the middle diff --git a/DataFormats/Legacy/HLT/include/AliceHLT/TPCRawCluster.h b/DataFormats/Legacy/HLT/include/AliceHLT/TPCRawCluster.h deleted file mode 100644 index 59be2a86c3c2b..0000000000000 --- a/DataFormats/Legacy/HLT/include/AliceHLT/TPCRawCluster.h +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -//-*- Mode: C++ -*- - -#ifndef TPCRAWCLUSTER_H -#define TPCRAWCLUSTER_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 * -//* * -//* 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 TPCRawCluster.h -// @author Matthias Richter -// @since 2015-09-27 -// @brief ALICE HLT TPC raw cluster structure and tools - -#include -#include // ifstream -#include // memcpy - -namespace o2 -{ -namespace AliceHLT -{ - -/** - * @struct RawCluster - * This is a redefinition from AliRoot/HLT/TPCLib/AliHLTTPCRawCluster.h for the - * sake of reading HLT TPC raw cluster files into O2. - * - * TODO: there is no dependence on AliRoot, however, a test needs to be added - * to check consistency if AliRoot is available in the build. - */ -struct RawCluster { - - int16_t GetPadRow() const { return fPadRow; } - float GetPad() const { return fPad; } - float GetTime() const { return fTime; } - float GetSigmaPad2() const { return fSigmaPad2; } - float GetSigmaTime2() const { return fSigmaTime2; } - int32_t GetCharge() const { return fCharge; } - int32_t GetQMax() const { return fQMax; } - bool GetFlagSplitPad() const { return (fFlags & (1 << 0)); } - bool GetFlagSplitTime() const { return (fFlags & (1 << 1)); } - bool GetFlagSplitAny() const { return (fFlags & 3); } - uint16_t GetFlags() const { return (fFlags); } - - int16_t fPadRow; - uint16_t fFlags; //Flags: (1 << 0): Split in pad direction - // (1 << 1): Split in time direction - //During cluster merging, flags are or'd - float fPad; - float fTime; - float fSigmaPad2; - float fSigmaTime2; - uint16_t fCharge; - uint16_t fQMax; -}; - -/** - * @struct RawClusterData - * Header data struct for a raw cluster block - */ -struct RawClusterData { - uint32_t fVersion; // version number - uint32_t fCount; // number of clusters - RawCluster fClusters[0]; // array of clusters -}; - -std::ostream& operator<<(std::ostream& stream, const RawCluster& cluster) -{ - stream << "TPCRawCluster:" - << " " << cluster.GetPadRow() - << " " << cluster.GetPad() - << " " << cluster.GetTime() - << " " << cluster.GetSigmaPad2() - << " " << cluster.GetSigmaTime2() - << " " << cluster.GetCharge() - << " " << cluster.GetQMax(); - return stream; -} - -/** - * @class RawClusterArray Wrapper to binary data block of HLT TPC raw clusters - * Container class which provides access to the content of a binary block of - * HLT TPC raw clusters. - */ -class RawClusterArray -{ - public: - RawClusterArray() : mBuffer(nullptr), mBufferSize(0), mNClusters(0), mClusters(NULL), mClustersEnd(NULL) {} - RawClusterArray(const char* filename) : mBuffer(nullptr), mBufferSize(0), mNClusters(0), mClusters(NULL), mClustersEnd(NULL) - { - init(filename); - } - RawClusterArray(unsigned char* buffer, int size) : mBuffer(nullptr), mBufferSize(0), mNClusters(0), mClusters(NULL), mClustersEnd(NULL) - { - init(buffer, size); - } - ~RawClusterArray() {} - - typedef uint8_t Buffer_t; - - int init(const char* filename) - { - std::ifstream input(filename, std::ifstream::binary); - clear(0); - if (input) { - // get length of file: - input.seekg(0, input.end); - int length = input.tellg(); - input.seekg(0, input.beg); - - // allocate memory: - mBuffer = new Buffer_t[length]; - mBufferSize = length; - - // read data as a block: - input.read(reinterpret_cast(mBuffer), length); - if (!input.good()) { - clear(-1); - std::cerr << "failed to read " << length << " byte(s) from file " << filename << std::endl; - } - - input.close(); - return init(); - } - std::cerr << "failed to open file " << filename << std::endl; - return -1; - } - - int init(unsigned char* buffer, int size) - { - if (!buffer || size <= 0) - return -1; - clear(0); - mBuffer = new Buffer_t[size]; - mBufferSize = size; - memcpy(mBuffer, buffer, size); - return init(); - } - - int GetNClusters() const { return mNClusters; } - - RawCluster* begin() { return mClusters; } - - RawCluster* end() { return mClustersEnd; } - - RawCluster& operator[](int i) - { - if (i + 1 > mNClusters) { - // runtime exeption? - static RawCluster dummy; - return dummy; - } - return *(mClusters + i); - } - - void print() { print(std::cout); } - - template - StreamT& print(StreamT& stream) - { - std::cout << "RawClusterArray: " << mNClusters << " cluster(s)" << std::endl; - for (RawCluster* cluster = mClusters; cluster != mClustersEnd; cluster++) { - std::cout << " " << *cluster << std::endl; - } - return stream; - } - - private: - int init() - { - if (mBuffer == nullptr || mBufferSize == 0) - return 0; - if (mBufferSize < sizeof(RawClusterData)) - return -1; - RawClusterData& clusterData = *reinterpret_cast(mBuffer); - - if (clusterData.fCount * sizeof(RawCluster) + sizeof(RawClusterData) > mBufferSize) { - std::cerr << "Format error, " << clusterData.fCount << " cluster(s) " - << "would require " - << (clusterData.fCount * sizeof(RawCluster) + sizeof(RawClusterData)) - << " byte(s), but only " << mBufferSize << " available" << std::endl; - return clear(-1); - } - - mNClusters = clusterData.fCount; - mClusters = clusterData.fClusters; - mClustersEnd = mClusters + mNClusters; - - return mNClusters; - } - - int clear(int returnValue) - { - mNClusters = 0; - mClusters = NULL; - mClustersEnd = NULL; - delete[] mBuffer; - mBuffer = nullptr; - mBufferSize = 0; - - return returnValue; - } - - Buffer_t* mBuffer; - int mBufferSize; - int mNClusters; - RawCluster* mClusters; - RawCluster* mClustersEnd; -}; - -}; // namespace AliceHLT -}; // namespace o2 -#endif diff --git a/DataFormats/MemoryResources/include/MemoryResources/MemoryResources.h b/DataFormats/MemoryResources/include/MemoryResources/MemoryResources.h index 42dd69aff38e3..b52f5c715575e 100644 --- a/DataFormats/MemoryResources/include/MemoryResources/MemoryResources.h +++ b/DataFormats/MemoryResources/include/MemoryResources/MemoryResources.h @@ -111,172 +111,16 @@ class MessageResource : public FairMQMemoryResource } }; -//__________________________________________________________________________________________________ -// A spectator pmr memory resource which only watches the memory of the underlying buffer, does not -// carry out real allocation. It owns the underlying buffer which is destroyed on deallocation. -template -class SpectatorMemoryResource : public boost::container::pmr::memory_resource -{ - public: - using buffer_type = BufferType; - - SpectatorMemoryResource() noexcept = delete; - SpectatorMemoryResource(const SpectatorMemoryResource&) noexcept = delete; - SpectatorMemoryResource(SpectatorMemoryResource&&) noexcept = default; - SpectatorMemoryResource& operator=(const SpectatorMemoryResource&) = delete; - SpectatorMemoryResource& operator=(SpectatorMemoryResource&&) = default; - ~SpectatorMemoryResource() noexcept override = default; - - // the resource is the pointer managed by unique_ptr - template - SpectatorMemoryResource(std::unique_ptr&& buffer, size_t size) - : mBuffer{std::move(buffer)}, mPointer{mBuffer.get()}, mSize{size} - { - } - - // the resource is the data of the vector managed by unique ptr - template - SpectatorMemoryResource(std::unique_ptr, typename buffer_type::deleter_type>&& buffer) - : mBuffer{std::move(buffer)}, mPointer{mBuffer->data()}, mSize{mBuffer->size() * sizeof(T)} - { - } - - // TODO: the underlying resource can be directly the vector or the read only buffer - protected: - void* do_allocate(std::size_t bytes, std::size_t /*alignment*/) override - { - if (mSize > 0) { - if (bytes > mSize) { - throw std::bad_alloc(); - } - mSize = 0; - return mPointer; - } - throw std::runtime_error("Can not allocate: this memory resource is only supposed to provide spectator access to external buffer"); - } - - void do_deallocate(void* p, std::size_t /*bytes*/, std::size_t /*alignment*/) override - { - if (p == mPointer) { - mBuffer.reset(); - mPointer = nullptr; - } else if (mPointer == nullptr) { - // there is an error in the logic flow, this should never be called more than once - throw std::logic_error("underlying controlled resource has been released already"); - } else { - throw std::logic_error("this resource can only deallocate the controlled resource pointer"); - } - } - bool do_is_equal(const memory_resource& /*other*/) const noexcept override - { - // uniquely owns the underlying resource, can never be equal to any other instance - return false; - } - - private: - buffer_type mBuffer; - void* mPointer = nullptr; - size_t mSize = 0; -}; - -//__________________________________________________________________________________________________ -// This in general (as in STL) is a bad idea, but here it is safe to inherit from an allocator since we -// have no additional data and only override some methods so we don't get into slicing and other problems. -template -class SpectatorAllocator : public boost::container::pmr::polymorphic_allocator -{ - public: - using boost::container::pmr::polymorphic_allocator::polymorphic_allocator; - using propagate_on_container_move_assignment = std::true_type; - - // 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 - void construct(U*) - { - } - - // dont try to call destructors, makes no sense since resource is managed externally AND allowed - // types cannot have side effects - template - void destroy(U*) - { - } - - T* allocate(size_t size) { return reinterpret_cast(this->resource()->allocate(size * sizeof(T), 64)); } - void deallocate(T* ptr, size_t size) - { - this->resource()->deallocate(const_cast::type*>(ptr), size); - } -}; - -//__________________________________________________________________________________________________ -/// This allocator has a pmr-like interface, but keeps the unique MessageResource as internal state, -/// allowing full resource (associated message) management internally without any global state. -template -class OwningMessageSpectatorAllocator -{ - public: - using value_type = T; - - MessageResource mResource; - - OwningMessageSpectatorAllocator() noexcept = default; - OwningMessageSpectatorAllocator(const OwningMessageSpectatorAllocator&) noexcept = default; - OwningMessageSpectatorAllocator(OwningMessageSpectatorAllocator&&) noexcept = default; - OwningMessageSpectatorAllocator(MessageResource&& resource) noexcept : mResource{resource} {} - - template - OwningMessageSpectatorAllocator(const OwningMessageSpectatorAllocator& other) noexcept : mResource(other.mResource) - { - } - - OwningMessageSpectatorAllocator& operator=(const OwningMessageSpectatorAllocator& other) - { - mResource = other.mResource; - return *this; - } - - OwningMessageSpectatorAllocator select_on_container_copy_construction() const - { - return OwningMessageSpectatorAllocator(); - } - - boost::container::pmr::memory_resource* resource() { return &mResource; } - - // 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 - void construct(U*) - { - } - - // dont try to call destructors, makes no sense since resource is managed externally AND allowed - // types cannot have side effects - template - void destroy(U*) - { - } - - T* allocate(size_t size) { return reinterpret_cast(mResource.allocate(size * sizeof(T), 64)); } - void deallocate(T* ptr, size_t size) - { - mResource.deallocate(const_cast::type*>(ptr), size); - } -}; - // The NoConstructAllocator behaves like the normal pmr vector but does not call constructors / destructors template -class NoConstructAllocator : public boost::container::pmr::polymorphic_allocator +class NoConstructAllocator : public fair::mq::pmr::polymorphic_allocator { public: - using boost::container::pmr::polymorphic_allocator::polymorphic_allocator; + using fair::mq::pmr::polymorphic_allocator::polymorphic_allocator; using propagate_on_container_move_assignment = std::true_type; template - NoConstructAllocator(Args&&... args) : boost::container::pmr::polymorphic_allocator(std::forward(args)...) + NoConstructAllocator(Args&&... args) : fair::mq::pmr::polymorphic_allocator(std::forward(args)...) { } @@ -301,20 +145,9 @@ class NoConstructAllocator : public boost::container::pmr::polymorphic_allocator //__________________________________________________________________________________________________ //__________________________________________________________________________________________________ -using ByteSpectatorAllocator = SpectatorAllocator; -using BytePmrAllocator = boost::container::pmr::polymorphic_allocator; +using BytePmrAllocator = fair::mq::pmr::polymorphic_allocator; template -using vector = std::vector>; - -//__________________________________________________________________________________________________ -/// Return a std::vector spanned over the contents of the message, takes ownership of the message -template -auto adoptVector(size_t nelem, fair::mq::MessagePtr message) -{ - static_assert(std::is_trivially_destructible::value); - return std::vector>( - nelem, OwningMessageSpectatorAllocator(MessageResource{std::move(message)})); -}; +using vector = std::vector>; //__________________________________________________________________________________________________ /// Get the allocator associated to a transport factory diff --git a/DataFormats/MemoryResources/test/testMemoryResources.cxx b/DataFormats/MemoryResources/test/testMemoryResources.cxx index 264fe59b1caac..a49cd00d75255 100644 --- a/DataFormats/MemoryResources/test/testMemoryResources.cxx +++ b/DataFormats/MemoryResources/test/testMemoryResources.cxx @@ -60,7 +60,7 @@ BOOST_AUTO_TEST_CASE(transportallocatormap_test) BOOST_CHECK(_tmp == allocZMQ); } -using namespace boost::container::pmr; +using namespace fair::mq::pmr; BOOST_AUTO_TEST_CASE(allocator_test) { @@ -88,15 +88,6 @@ BOOST_AUTO_TEST_CASE(allocator_test) } testData::nconstructions = 0; - { - std::vector> v(SpectatorAllocator{allocZMQ}); - v.reserve(3); - BOOST_CHECK(allocZMQ->getNumberOfMessages() == 1); - v.emplace_back(1); - v.emplace_back(2); - v.emplace_back(3); - BOOST_CHECK(testData::nconstructions == 3); - } BOOST_CHECK(allocZMQ->getNumberOfMessages() == 0); } @@ -147,73 +138,6 @@ BOOST_AUTO_TEST_CASE(getMessage_test) messageArray = static_cast(message->GetData()); BOOST_CHECK(messageArray[0] == 4 && messageArray[1] == 5 && messageArray[2] == 6); - { - std::vector> v(SpectatorAllocator{allocSHM}); - } -} - -BOOST_AUTO_TEST_CASE(adoptVector_test) -{ - size_t session{(size_t)getpid() * 1000 + 3}; - fair::mq::ProgOptions config; - config.SetProperty("session", std::to_string(session)); - - auto factoryZMQ = fair::mq::TransportFactory::CreateTransportFactory("zeromq"); - auto factorySHM = fair::mq::TransportFactory::CreateTransportFactory("shmem", "adoptVector_test", &config); - auto allocZMQ = getTransportAllocator(factoryZMQ.get()); - auto allocSHM = getTransportAllocator(factorySHM.get()); - - testData::nconstructions = 0; - - // Create a bogus message - auto message = factoryZMQ->CreateMessage(3 * sizeof(testData)); - auto messageAddr = message.get(); - testData tmpBuf[3] = {3, 2, 1}; - std::memcpy(message->GetData(), tmpBuf, 3 * sizeof(testData)); - - auto adoptedOwner = adoptVector(3, std::move(message)); - BOOST_CHECK(adoptedOwner[0].i == 3); - BOOST_CHECK(adoptedOwner[1].i == 2); - BOOST_CHECK(adoptedOwner[2].i == 1); - - auto reclaimedMessage = o2::pmr::getMessage(std::move(adoptedOwner)); - BOOST_CHECK(reclaimedMessage.get() == messageAddr); - BOOST_CHECK(adoptedOwner.size() == 0); - - auto modified = adoptVector(3, std::move(reclaimedMessage)); - modified.emplace_back(9); - BOOST_CHECK(modified[3].i == 9); - BOOST_CHECK(modified.size() == 4); - BOOST_CHECK(testData::nconstructions == 7); - auto modifiedMessage = getMessage(std::move(modified)); - BOOST_CHECK(modifiedMessage != nullptr); - BOOST_CHECK(modifiedMessage.get() != messageAddr); -} - -BOOST_AUTO_TEST_CASE(test_SpectatorMemoryResource) -{ - constexpr int size = 5; - auto buffer = std::make_unique(size); - auto const* bufferdata = buffer.get(); - SpectatorMemoryResource resource(std::move(buffer), size * sizeof(int)); - std::vector> bufferclone(size, o2::pmr::SpectatorAllocator(&resource)); - BOOST_CHECK(bufferclone.data() == bufferdata); - BOOST_CHECK(bufferclone.size() == size); - BOOST_CHECK_THROW(bufferclone.resize(2 * size), std::runtime_error); - - auto vecbuf = std::make_unique>(size); - auto const* vectordata = vecbuf->data(); - SpectatorMemoryResource vecresource(std::move(vecbuf)); - std::vector> vecclone(size, o2::pmr::SpectatorAllocator(&vecresource)); - BOOST_CHECK(vecclone.data() == vectordata); - BOOST_CHECK(vecclone.size() == size); - BOOST_CHECK_THROW(vecclone.resize(2 * size), std::runtime_error); - - std::vector> vecmove; - vecmove = std::move(vecclone); - BOOST_CHECK(vecclone.size() == 0); - BOOST_CHECK(vecmove.data() == vectordata); - BOOST_CHECK(vecmove.size() == size); } }; // namespace o2::pmr diff --git a/DataFormats/Parameters/include/DataFormatsParameters/AggregatedRunInfo.h b/DataFormats/Parameters/include/DataFormatsParameters/AggregatedRunInfo.h index e509be97a14fa..d0347114b5b4c 100644 --- a/DataFormats/Parameters/include/DataFormatsParameters/AggregatedRunInfo.h +++ b/DataFormats/Parameters/include/DataFormatsParameters/AggregatedRunInfo.h @@ -23,6 +23,7 @@ namespace o2::parameters { class GRPECSObject; +class GRPLHCIFData; /// Composite struct where one may collect important global properties of data "runs" /// aggregated from various sources (GRPECS, RunInformation CCDB entries, etc.). @@ -32,17 +33,36 @@ struct AggregatedRunInfo { int runNumber = 0; // run number int64_t sor = 0; // best known timestamp for the start of run int64_t eor = 0; // best known timestamp for end of run - int64_t orbitsPerTF = 0; // number of orbits per TF + int64_t orbitsPerTF = 0; // number of orbits per TF (takes precedence over that in GRPECS) int64_t orbitReset = 0; // timestamp of orbit reset before run int64_t orbitSOR = 0; // orbit when run starts after orbit reset int64_t orbitEOR = 0; // orbit when run ends after orbit reset // we may have pointers to actual data source objects GRPECS, ... const o2::parameters::GRPECSObject* grpECS = nullptr; // pointer to GRPECSobject (fetched during struct building) + const o2::parameters::GRPLHCIFData* grpLHC = nullptr; - // fills and returns AggregatedRunInfo for a given run number. - static AggregatedRunInfo buildAggregatedRunInfo(o2::ccdb::CCDBManagerInstance& ccdb, int runnumber); - static AggregatedRunInfo buildAggregatedRunInfo(int runnumber, long sorMS, long eorMS, long orbitResetMUS, const o2::parameters::GRPECSObject* grpecs, const std::vector* ctfFirstRunOrbitVec); + static AggregatedRunInfo buildAggregatedRunInfo(int runnumber, long sorMS, long eorMS, long orbitResetMUS, const o2::parameters::GRPECSObject* grpecs, const std::vector* ctfFirstRunOrbitVec, const o2::parameters::GRPLHCIFData* grplhcif = nullptr); + + // fills and returns AggregatedRunInfo for a given data run number. + static AggregatedRunInfo buildAggregatedRunInfo_DATA(o2::ccdb::CCDBManagerInstance& ccdb, int runnumber); + + // Returns the meta-data (MCProdInfo) associated to production lpm_prod_tag (performed by username) + static std::map getMCProdInfo(o2::ccdb::CCDBManagerInstance& ccdb, int runnumber, + std::string const& lpm_prod_tag, std::string const& username = "aliprod"); + + // function that adjusts with values from MC + void adjust_from_MC(o2::ccdb::CCDBManagerInstance& ccdb, int run_number, std::string const& lpm_prod_tag, std::string const& username = "aliprod"); + + // Fills and returns AggregatedRunInfo for a given run number. + // If a non-empty lpm_prod_tag is given, it will potentially override values with specifics from a + // MC production identified by that tag and username. + static AggregatedRunInfo buildAggregatedRunInfo(o2::ccdb::CCDBManagerInstance& ccdb, + int runnumber, + std::string const& lpm_prod_tag = "", + std::string const& username = "aliprod"); + + ClassDefNV(AggregatedRunInfo, 1); }; } // namespace o2::parameters diff --git a/DataFormats/Parameters/src/AggregatedRunInfo.cxx b/DataFormats/Parameters/src/AggregatedRunInfo.cxx index 22ce362b5d85a..40402a33af68b 100644 --- a/DataFormats/Parameters/src/AggregatedRunInfo.cxx +++ b/DataFormats/Parameters/src/AggregatedRunInfo.cxx @@ -15,13 +15,14 @@ #include "DataFormatsParameters/AggregatedRunInfo.h" #include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPECSObject.h" +#include "DataFormatsParameters/GRPLHCIFData.h" #include "CommonConstants/LHCConstants.h" #include "Framework/Logger.h" #include using namespace o2::parameters; -o2::parameters::AggregatedRunInfo AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::CCDBManagerInstance& ccdb, int runnumber) +o2::parameters::AggregatedRunInfo AggregatedRunInfo::buildAggregatedRunInfo_DATA(o2::ccdb::CCDBManagerInstance& ccdb, int runnumber) { // TODO: could think about caching results per runnumber to // avoid going to CCDB multiple times ---> but should be done inside the CCDBManagerInstance @@ -42,14 +43,15 @@ o2::parameters::AggregatedRunInfo AggregatedRunInfo::buildAggregatedRunInfo(o2:: std::map metadata; metadata["runNumber"] = Form("%d", runnumber); auto grpecs = ccdb.getSpecific("GLO/Config/GRPECS", run_mid_timestamp, metadata); + auto grplhcif = ccdb.getSpecific("GLO/Config/GRPLHCIF", run_mid_timestamp); // no run metadata here bool oldFatalState = ccdb.getFatalWhenNull(); ccdb.setFatalWhenNull(false); auto ctp_first_run_orbit = ccdb.getForTimeStamp>("CTP/Calib/FirstRunOrbit", run_mid_timestamp); ccdb.setFatalWhenNull(oldFatalState); - return buildAggregatedRunInfo(runnumber, sor, eor, tsOrbitReset, grpecs, ctp_first_run_orbit); + return buildAggregatedRunInfo(runnumber, sor, eor, tsOrbitReset, grpecs, ctp_first_run_orbit, grplhcif); } -o2::parameters::AggregatedRunInfo AggregatedRunInfo::buildAggregatedRunInfo(int runnumber, long sorMS, long eorMS, long orbitResetMUS, const o2::parameters::GRPECSObject* grpecs, const std::vector* ctfFirstRunOrbitVec) +o2::parameters::AggregatedRunInfo AggregatedRunInfo::buildAggregatedRunInfo(int runnumber, long sorMS, long eorMS, long orbitResetMUS, const o2::parameters::GRPECSObject* grpecs, const std::vector* ctfFirstRunOrbitVec, const o2::parameters::GRPLHCIFData* grplhcif) { auto nOrbitsPerTF = grpecs->getNHBFPerTF(); // calculate SOR/EOR orbits @@ -81,5 +83,69 @@ o2::parameters::AggregatedRunInfo AggregatedRunInfo::buildAggregatedRunInfo(int orbitSOR = (orbitSOR / nOrbitsPerTF + 1) * nOrbitsPerTF; } } - return AggregatedRunInfo{runnumber, sorMS, eorMS, nOrbitsPerTF, orbitResetMUS, orbitSOR, orbitEOR, grpecs}; + return AggregatedRunInfo{runnumber, sorMS, eorMS, nOrbitsPerTF, orbitResetMUS, orbitSOR, orbitEOR, grpecs, grplhcif}; +} + +namespace +{ + +// get path where to find MC production info +std::string getFullPath_MC(std::string const& username, std::string const& lpm_prod_tag) +{ + // construct the path where to lookup + std::string path = "/Users/" + std::string(1, username[0]) + "/" + username; + std::string fullpath = path + "/" + "MCProdInfo/" + lpm_prod_tag; + return fullpath; +} + +} // namespace + +std::map AggregatedRunInfo::getMCProdInfo(o2::ccdb::CCDBManagerInstance& ccdb, + int run_number, + std::string const& lpm_prod_tag, + std::string const& username) +{ + std::map metaDataFilter; + metaDataFilter["LPMProductionTag"] = lpm_prod_tag; + + // fetch the meta information for MC productions + auto header_data = ccdb.getCCDBAccessor().retrieveHeaders(getFullPath_MC(username, lpm_prod_tag), metaDataFilter, run_number); + return header_data; +} + +void AggregatedRunInfo::adjust_from_MC(o2::ccdb::CCDBManagerInstance& ccdb, + int run_number, + std::string const& lpm_prod_tag, + std::string const& username) +{ + auto header_data = AggregatedRunInfo::getMCProdInfo(ccdb, run_number, lpm_prod_tag, username); + + // adjust timeframe length if we find entry for MC production + auto iter = header_data.find("OrbitsPerTF"); + if (iter != header_data.end()) { + auto mc_orbitsPerTF = std::stoi(iter->second); + if (mc_orbitsPerTF != orbitsPerTF) { + LOG(info) << "Adjusting OrbitsPerTF from " << orbitsPerTF << " to " << mc_orbitsPerTF << " based on differing MC info"; + orbitsPerTF = mc_orbitsPerTF; + } + } else { + LOG(warn) << "No OrbitsPerTF information found for MC production " << lpm_prod_tag << " and run number " << run_number; + } +} + +AggregatedRunInfo AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::CCDBManagerInstance& ccdb, int run_number, std::string const& lpm_prod_tag, std::string const& username) +{ + // (a) lookup the AggregatedRunInfo for the data run + // (b) modify/overwrite the info object with MC specific settings if lpm_prod_tag is given + + auto original_info = buildAggregatedRunInfo_DATA(ccdb, run_number); + + if (lpm_prod_tag.size() == 0) { + return original_info; + } + + // in this case we adjust the info from MC + original_info.adjust_from_MC(ccdb, run_number, lpm_prod_tag, username); + + return original_info; } diff --git a/DataFormats/Parameters/src/GRPLHCIFData.cxx b/DataFormats/Parameters/src/GRPLHCIFData.cxx index 8e779ef452191..d39569f79376b 100644 --- a/DataFormats/Parameters/src/GRPLHCIFData.cxx +++ b/DataFormats/Parameters/src/GRPLHCIFData.cxx @@ -28,6 +28,8 @@ using namespace o2::constants::lhc; const std::unordered_map GRPLHCIFData::mZtoA = { {1, 1}, + {8, 16}, + {10, 20}, {82, 208}}; //_______________________________________________ diff --git a/DataFormats/Parameters/src/GRPTool.cxx b/DataFormats/Parameters/src/GRPTool.cxx index 903d659940558..e7561e6fc1ef6 100644 --- a/DataFormats/Parameters/src/GRPTool.cxx +++ b/DataFormats/Parameters/src/GRPTool.cxx @@ -312,7 +312,7 @@ bool create_GRPs(Options const& opts) auto soreor = ccdbmgr.getRunDuration(opts.run); runStart = soreor.first; grp.setTimeStart(runStart); - grp.setTimeEnd(runStart + 3600000); + grp.setTimeEnd(soreor.second); grp.setNHBFPerTF(opts.orbitsPerTF); std::vector modules{}; if (!o2::conf::SimConfig::determineActiveModulesList(opts.detectorList, opts.readout, std::vector(), modules)) { diff --git a/DataFormats/Reconstruction/CMakeLists.txt b/DataFormats/Reconstruction/CMakeLists.txt index 86c0831d2134e..d3ca8fdc70ad6 100644 --- a/DataFormats/Reconstruction/CMakeLists.txt +++ b/DataFormats/Reconstruction/CMakeLists.txt @@ -8,6 +8,7 @@ # In applying this license CERN does not waive the privileges and immunities # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +# add_compile_options(-O0 -g -fPIC) o2_add_library(ReconstructionDataFormats SOURCES src/TrackParametrization.cxx @@ -73,6 +74,7 @@ o2_target_root_dictionary( include/ReconstructionDataFormats/BCRange.h include/ReconstructionDataFormats/TrackHMP.h include/ReconstructionDataFormats/MatchInfoHMP.h + include/ReconstructionDataFormats/HelixHelper.h ) o2_add_test(Vertex diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/DCA.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/DCA.h index 922470f8992f5..6eb41b798e101 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/DCA.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/DCA.h @@ -14,10 +14,10 @@ #include "GPUCommonDef.h" #include "GPUCommonRtypes.h" -#include "GPUCommonArray.h" #ifndef GPUCA_GPUCODE_DEVICE #include +#include #endif /// \author ruben.shahoyan@cern.ch @@ -67,7 +67,7 @@ class DCA private: float mY = 0.f; float mZ = 0.f; - gpu::gpustd::array mCov; ///< s2y, syz, s2z + std::array mCov; ///< s2y, syz, s2z ClassDefNV(DCA, 1); }; diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/DecayNBodyIndex.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/DecayNBodyIndex.h index 31a4b8ebc44b3..5a5a8a9e64cca 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/DecayNBodyIndex.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/DecayNBodyIndex.h @@ -55,14 +55,19 @@ class DecayNBodyIndex class V0Index : public DecayNBodyIndex<2> { public: + enum V0Type : uint8_t { + kStandaloneV0 = 0, + kPhotonOnly, + kCollinear, + }; using DecayNBodyIndex<2>::DecayNBodyIndex; V0Index(int v, GIndex p, GIndex n) : DecayNBodyIndex<2>(v, {p, n}) {} - bool isStandaloneV0() const { return testBit(0); } - bool isPhotonOnly() const { return testBit(1); } - bool isCollinear() const { return testBit(2); } - void setStandaloneV0() { setBit(0); } - void setPhotonOnly() { setBit(1); } - void setCollinear() { setBit(2); } + bool isStandaloneV0() const { return testBit(kStandaloneV0); } + bool isPhotonOnly() const { return testBit(kPhotonOnly); } + bool isCollinear() const { return testBit(kCollinear); } + void setStandaloneV0() { setBit(kStandaloneV0); } + void setPhotonOnly() { setBit(kPhotonOnly); } + void setCollinear() { setBit(kCollinear); } ClassDefNV(V0Index, 1); }; diff --git a/Common/DCAFitter/include/DCAFitter/HelixHelper.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/HelixHelper.h similarity index 96% rename from Common/DCAFitter/include/DCAFitter/HelixHelper.h rename to DataFormats/Reconstruction/include/ReconstructionDataFormats/HelixHelper.h index bd710e459ac54..d197cba256c0e 100644 --- a/Common/DCAFitter/include/DCAFitter/HelixHelper.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/HelixHelper.h @@ -63,9 +63,10 @@ struct CrossInfo { { const auto& trcA = trax0.rC > trax1.rC ? trax0 : trax1; // designate the largest circle as A const auto& trcB = trax0.rC > trax1.rC ? trax1 : trax0; + nDCA = 0; float xDist = trcB.xC - trcA.xC, yDist = trcB.yC - trcA.yC; float dist2 = xDist * xDist + yDist * yDist, dist = o2::gpu::GPUCommonMath::Sqrt(dist2), rsum = trcA.rC + trcB.rC; - if (o2::gpu::GPUCommonMath::Sqrt(dist) < 1e-12) { + if (dist < 1e-12) { return nDCA; // circles are concentric? } if (dist > rsum) { // circles don't touch, chose a point in between @@ -75,9 +76,13 @@ struct CrossInfo { return nDCA; } notTouchingXY(dist, xDist, yDist, trcA, trcB.rC, isCollinear); - } 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 - notTouchingXY(dist, xDist, yDist, trcA, -trcB.rC, isCollinear); + } else if (auto dfr = dist + trcB.rC - trcA.rC; dfr < 0.) { // the small circle is nestled into large one w/o touching + if (dfr > -maxDistXY) { + // select the point of closest approach of 2 circles + notTouchingXY(dist, xDist, yDist, trcA, -trcB.rC, isCollinear); + } else { + return nDCA; + } } else { // 2 intersection points if (isCollinear) { /// collinear tracks, e.g. electrons from photon conversion @@ -89,7 +94,7 @@ struct CrossInfo { xDCA[0] = r2_r * trcA.xC + r1_r * trcB.xC; yDCA[0] = r2_r * trcA.yC + r1_r * trcB.yC; nDCA = 1; - } else if (o2::gpu::GPUCommonMath::Sqrt(xDist) < o2::gpu::GPUCommonMath::Sqrt(yDist)) { + } else if (o2::gpu::GPUCommonMath::Abs(xDist) < o2::gpu::GPUCommonMath::Abs(yDist)) { // to simplify calculations, we move to new frame x->x+Xc0, y->y+Yc0, so that // the 1st one is centered in origin float a = (trcA.rC * trcA.rC - trcB.rC * trcB.rC + dist2) / (2. * yDist), b = -xDist / yDist, ab = a * b, bb = b * b; @@ -167,7 +172,7 @@ struct CrossInfo { /// yL(t) = yL + t Ky; Ky = (sinAlp + cosAlp* snp/csp) /// zL(t) = zL + t Kz; Kz = tgl / csp /// Note that Kx^2 + Ky^2 + Kz^2 = (1+tgl^2) / csp^2 - + nDCA = 0; float dx = trax1.xC - trax0.xC; // for straight line TrackAuxPar stores lab coordinates at referene point!!! float dy = trax1.yC - trax0.yC; // float dz = tr1.getZ() - tr0.getZ(); diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOF.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOF.h index 1816e8604c0be..7bcfd7af0911a 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOF.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOF.h @@ -86,6 +86,14 @@ class MatchInfoTOF hasT0_1BCbefore = 0x1 << 8, hasT0_2BCbefore = 0x1 << 9 }; + void setFT0Best(double val, float res = 200.) + { + mFT0Best = val; + mFT0BestRes = res; + } + double getFT0Best() const { return mFT0Best; } + float getFT0BestRes() const { return mFT0BestRes; } + private: int mIdLocal; // track id in sector of the pair track-TOFcluster float mChi2; // chi2 of the pair track-TOFcluster @@ -106,7 +114,10 @@ class MatchInfoTOF float mTgeant = 0.0; ///< geant time in MC double mT0true = 0.0; ///< t0true - ClassDefNV(MatchInfoTOF, 8); + double mFT0Best = 0.0; //< best info for collision time + float mFT0BestRes = 200.0; //< resolution (in ps) of the best info for collision time + + ClassDefNV(MatchInfoTOF, 9); }; } // namespace dataformats } // namespace o2 diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertex.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertex.h index 5343d26ec5ce5..62de31d335e80 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertex.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertex.h @@ -42,7 +42,7 @@ class PrimaryVertex : public Vertex> float getZMAD() const { return mZMAD; } void setZMAD(float v) { mZMAD = v; } -#ifndef GPUCA_ALIGPUCODE +#ifndef GPUCA_GPUCODE_DEVICE void print() const; std::string asString() const; #endif @@ -56,7 +56,7 @@ class PrimaryVertex : public Vertex> ClassDefNV(PrimaryVertex, 2); }; -#ifndef GPUCA_ALIGPUCODE +#ifndef GPUCA_GPUCODE_DEVICE std::ostream& operator<<(std::ostream& os, const o2::dataformats::PrimaryVertex& v); #endif diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertexExt.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertexExt.h index bf47ed03f3b39..a228984f2ae5d 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertexExt.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertexExt.h @@ -36,7 +36,7 @@ struct PrimaryVertexExt : public PrimaryVertex { int getNSrcA(int i) const { return nSrcA[i]; } int getNSrcAU(int i) const { return nSrcAU[i]; } -#ifndef GPUCA_ALIGPUCODE +#ifndef GPUCA_GPUCODE_DEVICE void print() const; std::string asString() const; #endif @@ -44,7 +44,7 @@ struct PrimaryVertexExt : public PrimaryVertex { ClassDefNV(PrimaryVertexExt, 6); }; -#ifndef GPUCA_ALIGPUCODE +#ifndef GPUCA_GPUCODE_DEVICE std::ostream& operator<<(std::ostream& os, const o2::dataformats::PrimaryVertexExt& v); #endif diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackFwd.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackFwd.h index 76ca8473553cd..fca117583027f 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackFwd.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackFwd.h @@ -31,6 +31,12 @@ using SMatrix55Sym = ROOT::Math::SMatrix; using SMatrix5 = ROOT::Math::SVector; +template +class TrackParametrization; // fwd declaration for conversion method + +template +class TrackParametrizationWithError; // fwd declaration for conversion method + class TrackParFwd { // Forward track parameterization, kinematics only. public: @@ -42,6 +48,9 @@ class TrackParFwd TrackParFwd(TrackParFwd&&) = delete; TrackParFwd& operator=(TrackParFwd&&) = delete; + template + void toBarrelTrackPar(TrackParametrization& t) const; + /// return Z coordinate (cm) Double_t getZ() const { return mZ; } /// set Z coordinate (cm) @@ -145,6 +154,9 @@ class TrackParCovFwd : public TrackParFwd TrackParCovFwd& operator=(const TrackParCovFwd& tpf) = default; TrackParCovFwd(const Double_t z, const SMatrix5& parameters, const SMatrix55Sym& covariances, const Double_t chi2); + template + void toBarrelTrackParCov(TrackParametrizationWithError& t) const; + const SMatrix55Sym& getCovariances() const { return mCovariances; } void setCovariances(const SMatrix55Sym& covariances) { mCovariances = covariances; } void deleteCovariances() { mCovariances = SMatrix55Sym(); } @@ -161,6 +173,7 @@ class TrackParCovFwd : public TrackParFwd void propagateToZquadratic(double zEnd, double zField); void propagateToZhelix(double zEnd, double zField); void propagateToZ(double zEnd, double zField); // Parameters: helix; errors: quadratic + void propagateToDCAhelix(double zField, const std::array& p, std::array& dca); // Add Multiple Coulomb Scattering effects void addMCSEffect(double x2X0); diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrization.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrization.h index bfd56eb8f024f..918633d914230 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrization.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrization.h @@ -29,7 +29,6 @@ #include "GPUCommonDef.h" #include "GPUCommonRtypes.h" #include "GPUCommonMath.h" -#include "GPUCommonArray.h" #include "GPUROOTCartesianFwd.h" #ifndef GPUCA_GPUCODE_DEVICE @@ -39,6 +38,7 @@ #include #include #include +#include #endif #ifndef GPUCA_ALIGPUCODE // Used only by functions that are hidden on the GPU @@ -66,6 +66,9 @@ class DCA; namespace track { + +class TrackParFwd; // fwd declaration for conversion method + // aliases for track elements enum ParLabels : int { kY, kZ, @@ -119,6 +122,9 @@ constexpr float MaxPT = 100000.; // do not allow pTs exceeding constexpr float MinPTInv = 1. / MaxPT; // do not allow q/pTs less this value (to avoid NANs) constexpr float ELoss2EKinThreshInv = 1. / 0.025; // do not allow E.Loss correction step with dE/Ekin above the inverse of this value constexpr int MaxELossIter = 50; // max number of iteration for the ELoss to account for BB dependence on beta*gamma +constexpr float DefaultDCA = 999.f; // default DCA value +constexpr float DefaultDCACov = 999.f; // default DCA cov value + // uncomment this to enable correction for BB dependence on beta*gamma via BB derivative // #define _BB_NONCONST_CORR_ @@ -128,9 +134,9 @@ class TrackParametrization public: using value_t = value_T; - using dim2_t = gpu::gpustd::array; - using dim3_t = gpu::gpustd::array; - using params_t = gpu::gpustd::array; + using dim2_t = std::array; + using dim3_t = std::array; + using params_t = std::array; struct yzerr_t { // 2 measurement with error dim2_t yz; @@ -162,6 +168,8 @@ class TrackParametrization GPUd() value_t getTgl() const; GPUhd() value_t getQ2Pt() const; GPUd() value_t getCharge2Pt() const; + GPUd() value_t getR2() const; + GPUd() value_t getR() const; GPUd() int getAbsCharge() const; GPUd() PID getPID() const; GPUd() void setPID(const PID pid, bool passCharge = false); @@ -209,7 +217,7 @@ class TrackParametrization GPUd() math_utils::Point3D getXYZGlo() const; GPUd() void getXYZGlo(dim3_t& xyz) const; GPUd() bool getPxPyPzGlo(dim3_t& pxyz) const; - GPUd() bool getPosDirGlo(gpu::gpustd::array& posdirp) const; + GPUd() bool getPosDirGlo(std::array& posdirp) const; // methods for track params estimate at other point GPUd() bool getYZAt(value_t xk, value_t b, value_t& y, value_t& z) const; @@ -226,6 +234,7 @@ class TrackParametrization // parameters manipulation GPUd() bool correctForELoss(value_t xrho, bool anglecorr = false); GPUd() bool rotateParam(value_t alpha); + GPUd() bool rotateParam(value_t& alpha, value_t& ca, value_t& sa); GPUd() bool propagateParamTo(value_t xk, value_t b); GPUd() bool propagateParamTo(value_t xk, const dim3_t& b); GPUd() void invertParam(); @@ -246,8 +255,11 @@ class TrackParametrization GPUd() void printParam() const; GPUd() void printParamHexadecimal(); #ifndef GPUCA_ALIGPUCODE + void toFwdTrackPar(TrackParFwd& t) const; std::string asString() const; std::string asStringHexadecimal(); + size_t hash() const { return hash(getX(), getAlpha(), getY(), getZ(), getSnp(), getTgl(), getQ2Pt()); } + static size_t hash(float x, float alp, float y, float z, float snp, float tgl, float q2pt); #endif GPUd() void updateParam(value_t delta, int i); @@ -275,6 +287,7 @@ GPUdi() TrackParametrization::TrackParametrization(value_t x, value_t a : mX{x}, mAlpha{alpha}, mAbsCharge{char(gpu::CAMath::Abs(charge))}, mPID{pid} { // explicit constructor + math_utils::detail::bringToPMPi(mAlpha); for (int i = 0; i < kNParams; i++) { mP[i] = par[i]; } @@ -293,6 +306,7 @@ GPUdi() void TrackParametrization::set(value_t x, value_t alpha, const { mX = x; mAlpha = alpha; + math_utils::detail::bringToPMPi(mAlpha); mAbsCharge = char(gpu::CAMath::Abs(charge)); for (int i = 0; i < kNParams; i++) { mP[i] = par[i]; @@ -370,6 +384,20 @@ GPUdi() auto TrackParametrization::getCharge2Pt() const -> value_t return mAbsCharge ? mP[kQ2Pt] : 0.f; } +//____________________________________________________________ +template +GPUdi() auto TrackParametrization::getR2() const -> value_t +{ + return mX * mX + mP[kY] * mP[kY]; +} + +//____________________________________________________________ +template +GPUdi() auto TrackParametrization::getR() const -> value_t +{ + return gpu::CAMath::Sqrt(getR2()); +} + //____________________________________________________________ template GPUdi() int TrackParametrization::getAbsCharge() const @@ -428,6 +456,7 @@ template GPUdi() void TrackParametrization::setAlpha(value_t v) { mAlpha = v; + math_utils::detail::bringToPMPi(mAlpha); } //____________________________________________________________ @@ -752,6 +781,21 @@ GPUdi() void TrackParametrization::updateParams(const value_t* delta) } } +#ifndef GPUCA_ALIGPUCODE +template +size_t TrackParametrization::hash(float x, float alp, float y, float z, float snp, float tgl, float q2pt) +{ + size_t h = std::hash{}(o2::math_utils::detail::truncateFloatFraction(x, 0xFFFFFFF0)); + h ^= std::hash{}(o2::math_utils::detail::truncateFloatFraction(alp, 0xFFFFFFF0)) << 1; + h ^= std::hash{}(o2::math_utils::detail::truncateFloatFraction(y, 0xFFFFFFF0)) << 1; + h ^= std::hash{}(o2::math_utils::detail::truncateFloatFraction(z, 0xFFFFFFF0)) << 1; + h ^= std::hash{}(o2::math_utils::detail::truncateFloatFraction(snp, 0xFFFFFF00)) << 1; + h ^= std::hash{}(o2::math_utils::detail::truncateFloatFraction(tgl, 0xFFFFFF00)) << 1; + h ^= std::hash{}(o2::math_utils::detail::truncateFloatFraction(q2pt, 0xFFFFFC00)) << 1; + return h; +} +#endif + } // namespace track } // namespace o2 diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrizationWithError.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrizationWithError.h index cc783298e14cd..436dc42cff749 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrizationWithError.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrizationWithError.h @@ -25,6 +25,8 @@ namespace o2 namespace track { +class TrackParCovFwd; // fwd declaration for conversion method + template class TrackParametrizationWithError : public TrackParametrization { // track+error parameterization @@ -38,14 +40,14 @@ class TrackParametrizationWithError : public TrackParametrization static_assert(std::is_floating_point_v); #endif - using covMat_t = gpu::gpustd::array; + using covMat_t = std::array; using MatrixDSym5 = o2::math_utils::SMatrix>; using MatrixD5 = o2::math_utils::SMatrix>; GPUhd() 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& cv, int sign, bool sectorAlpha = true, const PID pid = PID::Pion); + const std::array& cv, int sign, bool sectorAlpha = true, const PID pid = PID::Pion); GPUhdDefault() TrackParametrizationWithError(const TrackParametrizationWithError& src) = default; GPUdDefault() TrackParametrizationWithError(TrackParametrizationWithError&& src) = default; @@ -57,7 +59,7 @@ class TrackParametrizationWithError : public TrackParametrization using TrackParametrization::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& cv, int sign, bool sectorAlpha = true, const PID pid = PID::Pion); + GPUd() void set(const dim3_t& xyz, const dim3_t& pxpypz, const std::array& 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; @@ -77,11 +79,12 @@ class TrackParametrizationWithError : public TrackParametrization GPUd() value_t getCovarElem(int i, int j) const; GPUd() value_t getDiagError2(int i) const; - GPUd() bool getCovXYZPxPyPzGlo(gpu::gpustd::array& c) const; + GPUd() bool getCovXYZPxPyPzGlo(std::array& c) const; GPUd() void print() const; GPUd() void printHexadecimal(); -#ifndef GPUCA_ALIGPUCODE +#ifndef GPUCA_GPUCODE_DEVICE + bool toFwdTrackParCov(TrackParCovFwd& t) const; std::string asString() const; std::string asStringHexadecimal(); #endif @@ -89,9 +92,14 @@ class TrackParametrizationWithError : public TrackParametrization // parameters + covmat manipulation GPUd() bool testRotate(value_t alpha) const; GPUd() bool rotate(value_t alpha); - GPUd() bool propagateTo(value_t xk, value_t b); + GPUd() bool rotate(value_t alpha, TrackParametrization& linRef, value_t bz); + GPUd() bool propagateTo(value_t xk, value_t bz); + GPUd() bool propagateTo(value_t xk, TrackParametrization& linRef, value_t bz); + GPUd() bool propagateTo(value_t xk, value_t bz, TrackParametrization* linRef) { return linRef ? propagateTo(xk, *linRef, bz) : propagateTo(xk, bz); } 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() bool propagateTo(value_t xk, TrackParametrization& linRef, const dim3_t& b); + GPUd() bool propagateTo(value_t xk, const dim3_t& b, TrackParametrization* linRef) { return linRef ? propagateTo(xk, *linRef, b) : propagateTo(xk, b); } + GPUd() bool propagateToDCA(const o2::dataformats::VertexBase& vtx, value_t bz, o2::dataformats::DCA* dca = nullptr, value_t maxD = 999.f); GPUd() void invert(); GPUd() value_t getPredictedChi2(const dim2_t& p, const dim3_t& cov) const; GPUd() value_t getPredictedChi2Quiet(const dim2_t& p, const dim3_t& cov) const; @@ -118,7 +126,7 @@ class TrackParametrizationWithError : public TrackParametrization GPUd() bool update(const BaseCluster& p); GPUd() bool correctForMaterial(value_t x2x0, value_t xrho, bool anglecorr = false); - + GPUd() bool correctForMaterial(TrackParametrization& linRef, value_t x2x0, value_t xrho, bool anglecorr = false); GPUd() void resetCovariance(value_t s2 = 0); GPUd() void checkCovariance(); GPUd() void checkCorrelations(); diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackUtils.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackUtils.h index 0ee0ca4461ab0..8a79130d64eda 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackUtils.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackUtils.h @@ -18,9 +18,9 @@ #define INCLUDE_RECONSTRUCTIONDATAFORMATS_TRACKUTILS_H_ #include "GPUCommonRtypes.h" -#include "GPUCommonArray.h" #ifndef GPUCA_GPUCODE_DEVICE +#include #include #endif @@ -39,11 +39,11 @@ template GPUd() value_T BetheBlochSolidOpt(value_T bg); template -GPUd() void g3helx3(value_T qfield, value_T step, gpu::gpustd::array& vect); +GPUd() void g3helx3(value_T qfield, value_T step, std::array& vect); //____________________________________________________ template -GPUd() void g3helx3(value_T qfield, value_T step, gpu::gpustd::array& vect) +GPUd() void g3helx3(value_T qfield, value_T step, std::array& vect) { /****************************************************************** * * diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h index d14bc7ac786c8..588a23d25a000 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h @@ -14,14 +14,17 @@ #include "GPUCommonDef.h" #include "GPUCommonMath.h" -#include "GPUCommonArray.h" #include #include "CommonDataFormat/TimeStamp.h" #ifndef GPUCA_GPUCODE_DEVICE -#include -#include #include +#include +#ifndef GPUCA_NO_FMT +#include +#include +#include +#endif #endif namespace o2 @@ -42,9 +45,17 @@ class VertexBase static constexpr int kNCov = 6; GPUhdDefault() VertexBase() = default; GPUhdDefault() ~VertexBase() = default; - GPUhd() VertexBase(const math_utils::Point3D& pos, const gpu::gpustd::array& cov) : mPos(pos), mCov(cov) + GPUhd() VertexBase(const float* pos, const float* cov) { + mPos = math_utils::Point3D(pos[0], pos[1], pos[2]); + mCov[kCovXX] = cov[kCovXX]; + mCov[kCovXY] = cov[kCovXY]; + mCov[kCovXZ] = cov[kCovXZ]; + mCov[kCovYY] = cov[kCovYY]; + mCov[kCovYZ] = cov[kCovYZ]; + mCov[kCovZZ] = cov[kCovZZ]; } + GPUhd() VertexBase(const math_utils::Point3D& pos, const std::array& cov) : mPos(pos), mCov(cov) {} #if !defined(GPUCA_NO_FMT) && !defined(GPUCA_GPUCODE_DEVICE) void print() const; @@ -55,6 +66,7 @@ class VertexBase GPUhd() float getX() const { return mPos.X(); } GPUhd() float getY() const { return mPos.Y(); } GPUhd() float getZ() const { return mPos.Z(); } + GPUhd() float getR() const { return gpu::CAMath::Hypot(mPos.X(), mPos.Y()); } GPUd() float getSigmaX2() const { return mCov[kCovXX]; } GPUd() float getSigmaY2() const { return mCov[kCovYY]; } GPUd() float getSigmaZ2() const { return mCov[kCovZZ]; } @@ -65,7 +77,8 @@ class VertexBase GPUd() float getSigmaY() const { return gpu::CAMath::Sqrt(getSigmaY2()); } GPUd() float getSigmaZ() const { return gpu::CAMath::Sqrt(getSigmaZ2()); } - GPUd() const gpu::gpustd::array& getCov() const { return mCov; } + GPUd() const std::array& getCov() const { return mCov; } + GPUd() float getCov(int e) const { return mCov[e]; } GPUd() math_utils::Point3D getXYZ() const { return mPos; } GPUd() math_utils::Point3D& getXYZ() { return mPos; } @@ -101,14 +114,15 @@ class VertexBase setSigmaXZ(sxz); setSigmaYZ(syz); } - GPUd() void setCov(const gpu::gpustd::array& cov) { mCov = cov; } + GPUd() void setCov(const std::array& cov) { mCov = cov; } + GPUd() void setCov(float c, int e) { mCov[e] = c; } bool operator==(const VertexBase& other) const; bool operator!=(const VertexBase& other) const { return !(*this == other); } protected: math_utils::Point3D mPos{0., 0., 0.}; ///< cartesian position - gpu::gpustd::array mCov{}; ///< errors, see CovElems enum + std::array mCov{}; ///< errors, see CovElems enum ClassDefNV(VertexBase, 1); }; @@ -130,12 +144,18 @@ class Vertex : public VertexBase GPUhdDefault() Vertex() = default; GPUhdDefault() ~Vertex() = default; - GPUhd() Vertex(const math_utils::Point3D& pos, const gpu::gpustd::array& cov, ushort nCont, float chi2) - : VertexBase(pos, cov), mChi2(chi2), mNContributors(nCont) + GPUhd() Vertex(const float* pos, const float* cov, ushort nCont, float chi2) : VertexBase(pos, cov), mChi2(chi2), mNContributors(nCont) {} + GPUhd() Vertex(const math_utils::Point3D& pos, const std::array& cov, ushort nCont, float chi2) : VertexBase(pos, cov), mChi2(chi2), mNContributors(nCont) {} + +#if !defined(GPUCA_NO_FMT) && !defined(GPUCA_GPUCODE_DEVICE) + void print() const; + std::string asString() const; +#endif + + GPUd() ushort getNContributors() const { + return mNContributors; } - - GPUd() ushort getNContributors() const { return mNContributors; } GPUd() void setNContributors(ushort v) { mNContributors = v; } GPUd() void addContributor() { mNContributors++; } @@ -162,6 +182,65 @@ class Vertex : public VertexBase #if !defined(GPUCA_GPUCODE_DEVICE) && !defined(GPUCA_NO_FMT) std::ostream& operator<<(std::ostream& os, const o2::dataformats::VertexBase& v); + +namespace detail +{ +template +concept Streamable = requires(std::ostream& os, const T& a) { + { + os << a + } + -> std::same_as; +}; + +template +concept HasFormattableTimeStamp = requires(const T& t) { + { + fmt::format("{}", t.getTimeStamp()) + } + -> std::convertible_to; +}; + +template +concept HasFormattableTimeStampWithError = requires(const T& t) { + { + fmt::format("{}+-{}", t.getTimeStamp(), t.getTimeStampError()) + } + -> std::convertible_to; +}; +} // namespace detail + +template +inline std::string Vertex::asString() const +{ + const std::string stamp = [&]() -> std::string { + if constexpr (detail::Streamable) { + std::ostringstream oss; + oss << mTimeStamp; + return oss.str(); + } else if constexpr (detail::HasFormattableTimeStampWithError) { + return fmt::format("{}+-{}", mTimeStamp.getTimeStamp(), mTimeStamp.getTimeStampError()); + } else if constexpr (detail::HasFormattableTimeStamp) { + return fmt::format("{}", mTimeStamp.getTimeStamp()); + } else { + return "X"; + } + }(); + return fmt::format("{} NContrib:{} Chi2:{:.2f} Flags:{:b} Stamp:{}", VertexBase::asString(), mNContributors, mChi2, mBits, stamp); +} + +template +inline std::ostream& operator<<(std::ostream& os, const o2::dataformats::Vertex& v) +{ + os << v.asString(); + return os; +} + +template +inline void Vertex::print() const +{ + std::cout << *this << '\n'; +} #endif } // namespace dataformats diff --git a/DataFormats/Reconstruction/src/DCA.cxx b/DataFormats/Reconstruction/src/DCA.cxx index 9bb324c8df3a9..dd7c959add253 100644 --- a/DataFormats/Reconstruction/src/DCA.cxx +++ b/DataFormats/Reconstruction/src/DCA.cxx @@ -20,20 +20,16 @@ namespace o2 namespace dataformats { -#ifndef GPUCA_GPUCODE_DEVICE std::ostream& operator<<(std::ostream& os, const o2::dataformats::DCA& d) { // stream itself os << "DCA YZ {" << d.getY() << ", " << d.getZ() << "} Cov {" << d.getSigmaY2() << ", " << d.getSigmaYZ() << ", " << d.getSigmaZ2() << "}"; return os; } -#endif void DCA::print() const { -#ifndef GPUCA_GPUCODE_DEVICE std::cout << *this << '\n'; -#endif } } // namespace dataformats diff --git a/DataFormats/Reconstruction/src/Decay3Body.cxx b/DataFormats/Reconstruction/src/Decay3Body.cxx index aa071cea675cd..eb1b7ea1fd57d 100644 --- a/DataFormats/Reconstruction/src/Decay3Body.cxx +++ b/DataFormats/Reconstruction/src/Decay3Body.cxx @@ -16,15 +16,14 @@ using namespace o2::dataformats; Decay3Body::Decay3Body(const std::array& xyz, const std::array& pxyz, const std::array& covxyz, const Track& tr0, const Track& tr1, const Track& tr2, o2::track::PID pid) : mProngs{tr0, tr1, tr2} { - std::array cov{}, cov1{}, cov2{}; - tr0.getCovXYZPxPyPzGlo(cov); + std::array cov{}, cov0{}, cov1{}, cov2{}; + tr0.getCovXYZPxPyPzGlo(cov0); tr1.getCovXYZPxPyPzGlo(cov1); tr2.getCovXYZPxPyPzGlo(cov2); - for (int i = 0; i < 21; i++) { - cov[i] += cov1[i] + cov2[i]; - } + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component for (int i = 0; i < 6; i++) { cov[i] = covxyz[i]; + cov[MomInd[i]] = cov0[MomInd[i]] + cov1[MomInd[i]] + cov2[MomInd[i]]; } this->set(xyz, pxyz, cov, tr0.getCharge() + tr1.getCharge() + tr2.getCharge(), true, pid); } diff --git a/DataFormats/Reconstruction/src/PrimaryVertex.cxx b/DataFormats/Reconstruction/src/PrimaryVertex.cxx index f1b1a8ff01181..f6f589fcb038a 100644 --- a/DataFormats/Reconstruction/src/PrimaryVertex.cxx +++ b/DataFormats/Reconstruction/src/PrimaryVertex.cxx @@ -19,8 +19,6 @@ namespace o2 namespace dataformats { -#ifndef GPUCA_ALIGPUCODE - std::string PrimaryVertex::asString() const { auto str = o2::utils::Str::concat_string(VertexBase::asString(), @@ -44,7 +42,5 @@ void PrimaryVertex::print() const std::cout << *this << std::endl; } -#endif - } // namespace dataformats } // namespace o2 diff --git a/DataFormats/Reconstruction/src/PrimaryVertexExt.cxx b/DataFormats/Reconstruction/src/PrimaryVertexExt.cxx index 6065f04a3bc1a..31f0eff191591 100644 --- a/DataFormats/Reconstruction/src/PrimaryVertexExt.cxx +++ b/DataFormats/Reconstruction/src/PrimaryVertexExt.cxx @@ -18,8 +18,6 @@ namespace o2 { namespace dataformats { - -#ifndef GPUCA_ALIGPUCODE using GTrackID = o2::dataformats::GlobalTrackID; std::string PrimaryVertexExt::asString() const @@ -45,7 +43,5 @@ void PrimaryVertexExt::print() const std::cout << *this << std::endl; } -#endif - } // namespace dataformats } // namespace o2 diff --git a/DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h b/DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h index 6cd72e8668cc1..b386830d9872d 100644 --- a/DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h +++ b/DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h @@ -117,4 +117,7 @@ #pragma link C++ class o2::dataformats::StrangeTrack + ; #pragma link C++ class std::vector < o2::dataformats::StrangeTrack> + ; +#pragma link C++ class o2::track::TrackAuxPar + ; +#pragma link C++ class o2::track::CrossInfo + ; + #endif diff --git a/DataFormats/Reconstruction/src/TrackFwd.cxx b/DataFormats/Reconstruction/src/TrackFwd.cxx index 3c45a8ecb6ec2..511ba122b2822 100644 --- a/DataFormats/Reconstruction/src/TrackFwd.cxx +++ b/DataFormats/Reconstruction/src/TrackFwd.cxx @@ -10,7 +10,10 @@ // or submit itself to any jurisdiction. #include "ReconstructionDataFormats/TrackFwd.h" +#include "ReconstructionDataFormats/TrackParametrization.h" +#include "ReconstructionDataFormats/TrackParametrizationWithError.h" #include "Math/MatrixFunctions.h" +#include namespace o2 { @@ -40,7 +43,7 @@ void TrackParFwd::propagateParamToZlinear(double zEnd) auto dZ = (zEnd - getZ()); auto phi0 = getPhi(); auto [sinphi0, cosphi0] = o2::math_utils::sincosd(phi0); - auto invtanl0 = 1.0 / getTanl(); + auto invtanl0 = 1.0 / getTgl(); auto n = dZ * invtanl0; mParameters(0) += n * cosphi0; mParameters(1) += n * sinphi0; @@ -503,5 +506,147 @@ bool TrackParCovFwd::getCovXYZPxPyPzGlo(std::array& cv) const return true; } +//________________________________________________________________ + +void TrackParCovFwd::propagateToDCAhelix(double zField, const std::array& p, std::array& dca) +{ + // Computing DCA of fwd track w.r.t vertex in helix track model, using Newton-Raphson minimization + + auto x0 = mParameters(0); + auto y0 = mParameters(1); + auto z0 = mZ; + auto phi0 = mParameters(2); + auto tanl = mParameters(3); + auto qOverPt = mParameters(4); + auto k = TMath::Abs(o2::constants::math::B2C * zField); + auto qpt = 1.0 / qOverPt; + auto qR = qpt / std::fabs(k); + auto invtanl = 1.0 / tanl; + auto Hz = std::copysign(1, zField); + + auto xPV = p[0]; + auto yPV = p[1]; + auto zPV = p[2]; + + auto qRtanl = qR * tanl; + auto invqRtanl = 1.0 / qRtanl; + auto [sinp, cosp] = o2::math_utils::sincosd(phi0); + + auto z = zPV; + double tol = 1e-4; + int max_iter = 10; + int iter = 0; + + while (iter++ < max_iter) { + double theta = (z0 - z) * invqRtanl; + double phi_theta = phi0 + Hz * theta; + double sin_phi_theta = sin(phi_theta); + double cos_phi_theta = cos(phi_theta); + + double DX = x0 - Hz * qR * (sin_phi_theta - sinp) - xPV; + double DY = y0 + Hz * qR * (cos_phi_theta - cosp) - yPV; + double DZ = z - zPV; + + double dD2_dZ = + 2 * DX * cos_phi_theta * invtanl + + 2 * DY * sin_phi_theta * invtanl + + 2 * DZ; + + double d2D2_dZ2 = + 2 * invtanl * invtanl + + 2 * invtanl * (DX * Hz * sin_phi_theta - DY * Hz * cos_phi_theta) * invqRtanl + + 2; + + double z_new = z - dD2_dZ / d2D2_dZ2; + + if (std::abs(z_new - z) < tol) { + z = z_new; + this->propagateToZhelix(z, zField); + dca[0] = this->getX() - xPV; + dca[1] = this->getY() - yPV; + dca[2] = this->getZ() - zPV; + LOG(debug) << "Converged after " << iter << " iterations for vertex X=" << p[0] << ", Y=" << p[1] << ", Z = " << p[2]; + return; + } + z = z_new; + } + LOG(debug) << "Failed to converge after " << iter << " iterations for vertex X=" << p[0] << ", Y=" << p[1] << ", Z = " << p[2]; + return; +} + +template +void TrackParFwd::toBarrelTrackPar(TrackParametrization& t) const +{ + // we select the barrel frame with alpha = phi, then by construction the snp is 0 + auto alpha = getPhi(); + auto csa = TMath::Cos(alpha), sna = TMath::Sin(alpha); + t.setAlpha(alpha); + t.setX(csa * getX() + sna * getY()); + t.setY(-sna * getX() + csa * getY()); + t.setZ(getZ()); + t.setSnp(0); + t.setTgl(getTanl()); + t.setQ2Pt(getInvQPt()); +} + +template +void TrackParCovFwd::toBarrelTrackParCov(TrackParametrizationWithError& t) const +{ + // We select the barrel frame with alpha = phi, then by construction the snp is 0 + auto alpha = getPhi(); + auto csa = TMath::Cos(alpha), sna = TMath::Sin(alpha); + t.setAlpha(alpha); + t.setX(csa * getX() + sna * getY()); + t.setY(-sna * getX() + csa * getY()); + t.setZ(getZ()); + t.setSnp(0); + t.setTgl(getTgl()); + t.setQ2Pt(getInvQPt()); + /* + The standard Jacobian d{barrel_param} / d{fwd_param} should be augmented by the "forward" uncertainty + in X_barrel translated to uncertainty in Z, i.e: + A fwd param variation delta_x, delta_y leads to barrel frame coordinate variaion + delta_xb = csa delta_x + sna delta_y + delta_yb = -sna delta_x + csa delta_y + with dx_b/dz = csp/tgL = 1/tgL, dy_b/dz = snp/tgL = 0 (for phi 0 in the tracking frame) the variation of delta_xb would require + a shift in delta_zb = -tgL delta_xb to stat at the same X. + So, for alpha=phi (-> snp=0) choice the full Jacobian fwd->barrel is: + / -sna csa 0 0 0 \ + | -tgL*csa -tgL*sna 0 0 0 | + | 0 0 1 0 0 | + | 0 0 0 1 0 | + \ 0 0 0 0 1 / + */ + const T a1 = -sna; + const T a2 = csa; + const T b1 = -getTgl() * csa; + const T b2 = -getTgl() * sna; + const T cphi = 1; + const auto& C = getCovariances(); + typename TrackParametrizationWithError::covMat_t covBarrel = { + T(a1 * a1 * C(0, 0) + 2 * a1 * a2 * C(0, 1) + a2 * a2 * C(1, 1)), // kSigY2 + T(a1 * b1 * C(0, 0) + (a1 * b2 + a2 * b1) * C(0, 1) + a2 * b2 * C(1, 1)), // kSigZY + T(b1 * b1 * C(0, 0) + 2 * b1 * b2 * C(0, 1) + b2 * b2 * C(1, 1)), // kSigZ2 + T(csa * (a1 * C(0, 2) + a2 * C(1, 2))), // kSigSnpY + T(csa * (b1 * C(0, 2) + b2 * C(1, 2))), // kSigSnpZ + T(csa * csa * C(2, 2)), // kSigSnp2 + T(a1 * C(0, 3) + a2 * C(1, 3)), // kSigTglY + T(b1 * C(0, 3) + b2 * C(1, 3)), // kSigTglZ + T(csa * C(2, 3)), // kSigTglSnp + T(C(3, 3)), // kSigTgl2 + T(a1 * C(0, 4) + a2 * C(1, 4)), // kSigQ2PtY + T(b1 * C(0, 4) + b2 * C(1, 4)), // kSigQ2PtZ + T(csa * C(2, 4)), // kSigQ2PtSnp + T(C(3, 4)), // kSigQ2PtTgl + T(C(4, 4)) // kSigQ2Pt2 + }; + t.setCov(covBarrel); +} + +template void TrackParFwd::toBarrelTrackPar(TrackParametrization&) const; +template void TrackParFwd::toBarrelTrackPar(TrackParametrization&) const; +template void TrackParCovFwd::toBarrelTrackParCov(TrackParametrizationWithError&) const; +template void TrackParCovFwd::toBarrelTrackParCov(TrackParametrizationWithError&) const; + } // namespace track } // namespace o2 diff --git a/DataFormats/Reconstruction/src/TrackParametrization.cxx b/DataFormats/Reconstruction/src/TrackParametrization.cxx index 4b68ea425bfbd..c238b087d5086 100644 --- a/DataFormats/Reconstruction/src/TrackParametrization.cxx +++ b/DataFormats/Reconstruction/src/TrackParametrization.cxx @@ -26,6 +26,7 @@ #ifndef GPUCA_ALIGPUCODE #include +#include "ReconstructionDataFormats/TrackFwd.h" #endif using namespace o2::gpu; @@ -130,7 +131,7 @@ GPUd() bool TrackParametrization::getPxPyPzGlo(dim3_t& pxyz) const //____________________________________________________ template -GPUd() bool TrackParametrization::getPosDirGlo(gpu::gpustd::array& posdirp) const +GPUd() bool TrackParametrization::getPosDirGlo(std::array& posdirp) const { // fill vector with lab x,y,z,px/p,py/p,pz/p,p,sinAlpha,cosAlpha value_t ptI = getPtInv(); @@ -188,6 +189,38 @@ GPUd() bool TrackParametrization::rotateParam(value_t alpha) return true; } +//______________________________________________________________ +template +GPUd() bool TrackParametrization::rotateParam(value_t& alpha, value_t& ca, value_t& sa) +{ + // rotate to alpha frame + if (gpu::CAMath::Abs(getSnp()) > constants::math::Almost1) { + LOGP(debug, "Precondition is not satisfied: |sin(phi)|>1 ! {:f}", getSnp()); + return false; + } + // + math_utils::detail::bringToPMPi(alpha); + math_utils::detail::sincos(alpha - getAlpha(), sa, ca); + value_t snp = 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) { + // LOGF(warning,"Rotation failed: local cos(phi) would become {:.2f}", csp * ca + snp * sa); + return false; + } + // + value_t tmp = snp * ca - csp * sa; + if (gpu::CAMath::Abs(tmp) > constants::math::Almost1) { + LOGP(debug, "Rotation failed: new snp {:.2f}", tmp); + return false; + } + value_t xold = getX(), yold = getY(); + mAlpha = alpha; + mX = xold * ca + yold * sa; + mP[kY] = -xold * sa + yold * ca; + mP[kSnp] = tmp; + return true; +} + //____________________________________________________________ template GPUd() bool TrackParametrization::propagateParamTo(value_t xk, const dim3_t& b) @@ -231,7 +264,7 @@ GPUd() bool TrackParametrization::propagateParamTo(value_t xk, const di step *= gpu::CAMath::Sqrt(1.f + getTgl() * getTgl()); // // get the track x,y,z,px/p,py/p,pz/p,p,sinAlpha,cosAlpha in the Global System - gpu::gpustd::array vecLab{0.f}; + std::array vecLab{0.f}; if (!getPosDirGlo(vecLab)) { return false; } @@ -250,7 +283,7 @@ GPUd() bool TrackParametrization::propagateParamTo(value_t xk, const di costet = b[2] / bb; sintet = bt / bb; } - gpu::gpustd::array vect{costet * cosphi * vecLab[0] + costet * sinphi * vecLab[1] - sintet * vecLab[2], + std::array 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], @@ -282,14 +315,14 @@ GPUd() bool TrackParametrization::propagateParamTo(value_t xk, const di // Do the final correcting step to the target plane (linear approximation) value_t x = vecLab[0], y = vecLab[1], z = vecLab[2]; - if (gpu::CAMath::Abs(dx) > constants::math::Almost0) { + if (gpu::CAMath::Abs(x - xk) > constants::math::Almost0) { if (gpu::CAMath::Abs(vecLab[3]) < constants::math::Almost0) { return false; } - dx = xk - vecLab[0]; - x += dx; - y += vecLab[4] / vecLab[3] * dx; - z += vecLab[5] / vecLab[3] * dx; + auto dxFin = xk - vecLab[0]; + x += dxFin; + y += vecLab[4] / vecLab[3] * dxFin; + z += vecLab[5] / vecLab[3] * dxFin; } // Calculate the track parameters @@ -378,6 +411,10 @@ GPUd() bool TrackParametrization::propagateParamToDCA(const math_utils: // Estimate the impact parameter neglecting the track curvature value_t d = gpu::CAMath::Abs(x * snp - y * csp); if (d > maxD) { + if (dca) { // provide default DCA for failed propag + (*dca)[0] = o2::track::DefaultDCA; + (*dca)[1] = o2::track::DefaultDCA; + } return false; } value_t crv = getCurvature(b); @@ -399,6 +436,10 @@ GPUd() bool TrackParametrization::propagateParamToDCA(const math_utils: #else LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << " for vertex " << vtx.X() << ' ' << vtx.Y() << ' ' << vtx.Z(); #endif + if (dca) { // provide default DCA for failed propag + (*dca)[0] = o2::track::DefaultDCA; + (*dca)[1] = o2::track::DefaultDCA; + } return false; } *this = tmpT; @@ -575,7 +616,7 @@ template std::string TrackParametrization::asString() const { // print parameters as string - return fmt::format("X:{:+.4e} Alp:{:+.3e} Par: {:+.4e} {:+.4e} {:+.4e} {:+.4e} {:+.4e} |Q|:{:d} {:s}\n", + return fmt::format("X:{:+.4e} Alp:{:+.3e} Par: {:+.4e} {:+.4e} {:+.4e} {:+.4e} {:+.4e} |Q|:{:d} {:s}", getX(), getAlpha(), getY(), getZ(), getSnp(), getTgl(), getQ2Pt(), getAbsCharge(), getPID().getName()); } @@ -651,7 +692,7 @@ GPUd() bool TrackParametrization::getXatLabR(value_t r, value_t& x, val // DirOutward (==1) - go along the track (increasing mX) // DirInward (==-1) - go backward (decreasing mX) // - const auto fy = mP[0], sn = mP[2]; + const double fy = mP[0], sn = mP[2]; const value_t kEps = 1.e-6; // if (gpu::CAMath::Abs(getSnp()) > constants::math::Almost1) { @@ -670,18 +711,18 @@ GPUd() bool TrackParametrization::getXatLabR(value_t r, value_t& x, val if (r0 <= constants::math::Almost0) { return false; // the track is concentric to circle } - value_t tR2r0 = 1.f, g = 0.f, tmp = 0.f; + double tR2r0 = 1., g = 0., tmp = 0.; if (gpu::CAMath::Abs(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; } else { tR2r0 = 1.0; - g = 0.5f * r * r / (r0 * circle.rC) - 1.f; - tmp = 0.5f * r * r / (r0 * r0); + g = 0.5 * r * r / (r0 * circle.rC) - 1.; + tmp = 0.5 * r * r / (r0 * r0); } - value_t det = (1.f - g) * (1.f + g); - if (det < 0.f) { + auto det = (1. - g) * (1. + g); + if (det < 0.) { return false; // does not reach raduis r } det = gpu::CAMath::Sqrt(det); @@ -691,25 +732,26 @@ GPUd() bool TrackParametrization::getXatLabR(value_t r, value_t& x, val // where s0 and c0 make direction for the circle center (=circle.xC/r0 and circle.yC/r0) // x = circle.xC * tmp; - value_t y = circle.yC * tmp; + auto y = circle.yC * tmp; if (gpu::CAMath::Abs(circle.yC) > constants::math::Almost0) { // when circle.yC==0 the x,y is unique - value_t dfx = tR2r0 * gpu::CAMath::Abs(circle.yC) * det; - value_t dfy = tR2r0 * circle.xC * (circle.yC > 0.f ? det : -det); + auto dfx = tR2r0 * gpu::CAMath::Abs(circle.yC) * det; + auto dfy = tR2r0 * circle.xC * (circle.yC > 0. ? 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 - x += delta < 0.f ? dfx : -dfx; + auto delta = (x - mX) * dfx - (y - fy) * dfy; // the choice of + in C will lead to smaller step if delta<0 + x += delta < 0. ? dfx : -dfx; } else if (dir == DirOutward) { // along track direction: x must be > mX x -= dfx; // try the smallest step (dfx is positive) - value_t dfeps = mX - x; // handle special case of very small step + auto dfeps = mX - x; // handle special case of very small step if (dfeps < -kEps) { return true; } if (gpu::CAMath::Abs(dfeps) < kEps && gpu::CAMath::Abs(mX * mX + fy * fy - r * r) < kEps) { // are we already in right r? - return mX; + x = mX; + return true; } x += dfx + dfx; - value_t dxm = x - mX; - if (dxm > 0.f) { + auto dxm = x - mX; + if (dxm > 0.) { return true; } else if (dxm < -kEps) { return false; @@ -717,16 +759,17 @@ GPUd() bool TrackParametrization::getXatLabR(value_t r, value_t& x, val x = mX; // don't move } else { // backward: x must be < mX x += dfx; // try the smallest step (dfx is positive) - value_t dfeps = x - mX; // handle special case of very small step + auto dfeps = x - mX; // handle special case of very small step if (dfeps < -kEps) { return true; } if (gpu::CAMath::Abs(dfeps) < kEps && gpu::CAMath::Abs(mX * mX + fy * fy - r * r) < kEps) { // are we already in right r? - return mX; + x = mX; + return true; } x -= dfx + dfx; - value_t dxm = x - mX; - if (dxm < 0.f) { + auto dxm = x - mX; + if (dxm < 0.) { return true; } if (dxm > kEps) { @@ -739,11 +782,11 @@ GPUd() bool TrackParametrization::getXatLabR(value_t r, value_t& x, val return false; } } - return x; + return true; } // this is a straight track if (gpu::CAMath::Abs(sn) >= constants::math::Almost1) { // || to Y axis - value_t det = (r - mX) * (r + mX); + double det = (r - mX) * (r + mX); if (det < 0.f) { return false; // does not reach raduis r } @@ -753,7 +796,7 @@ GPUd() bool TrackParametrization::getXatLabR(value_t r, value_t& x, val } det = gpu::CAMath::Sqrt(det); if (dir == DirOutward) { // along the track direction - if (sn > 0.f) { + if (sn > 0.) { if (fy > det) { return false; // track is along Y axis and above the circle } @@ -763,7 +806,7 @@ GPUd() bool TrackParametrization::getXatLabR(value_t r, value_t& x, val } } } else if (dir == DirInward) { // against track direction - if (sn > 0.f) { + if (sn > 0.) { if (fy < -det) { return false; // track is along Y axis } @@ -772,13 +815,13 @@ GPUd() bool TrackParametrization::getXatLabR(value_t r, value_t& x, val } } } else if (gpu::CAMath::Abs(sn) <= constants::math::Almost0) { // || to X axis - value_t det = (r - fy) * (r + fy); - if (det < 0.f) { + double det = (r - fy) * (r + fy); + if (det < 0.) { return false; // does not reach raduis r } det = gpu::CAMath::Sqrt(det); if (dir == DirAuto) { - x = mX > 0.f ? det : -det; // choose the solution requiring the smalest step + x = mX > 0. ? det : -det; // choose the solution requiring the smalest step return true; } else if (dir == DirOutward) { // along the track direction if (mX > det) { @@ -794,17 +837,17 @@ GPUd() bool TrackParametrization::getXatLabR(value_t r, value_t& x, val } } } else { // general case of straight line - value_t cs = gpu::CAMath::Sqrt((1.f - sn) * (1.f + sn)); - value_t xsyc = mX * sn - fy * cs; - value_t det = (r - xsyc) * (r + xsyc); - if (det < 0.f) { + auto cs = gpu::CAMath::Sqrt((1. - sn) * (1. + sn)); + auto xsyc = mX * sn - fy * cs; + auto det = (r - xsyc) * (r + xsyc); + if (det < 0.) { return false; // does not reach raduis r } det = gpu::CAMath::Sqrt(det); - value_t xcys = mX * cs + fy * sn; - value_t t = -xcys; + auto xcys = mX * cs + fy * sn; + auto t = -xcys; if (dir == DirAuto) { - t += t > 0.f ? -det : det; // chose the solution requiring the smalest step + t += t > 0. ? -det : det; // chose the solution requiring the smalest step } else if (dir > 0) { // go in increasing mX direction. ( t+-det > 0) if (t >= -det) { t += det; // take minimal step giving t>0 @@ -943,6 +986,21 @@ GPUd() typename TrackParametrization::value_t TrackParametrization +void TrackParametrization::toFwdTrackPar(TrackParFwd& t) const +{ + auto p = getXYZGlo(); + t.setZ(p.Z()); + t.setX(p.X()); + t.setY(p.Y()); + t.setPhi(getPhi()); + t.setTanl(getTgl()); + t.setInvQPt(getQ2Pt()); +} +#endif + namespace o2::track { #if !defined(GPUCA_GPUCODE) || defined(GPUCA_GPUCODE_DEVICE) // FIXME: DR: WORKAROUND to avoid CUDA bug creating host symbols for device code. diff --git a/DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx b/DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx index 81963adf79938..ee2e96736aa6d 100644 --- a/DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx +++ b/DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx @@ -21,6 +21,7 @@ #ifndef GPUCA_ALIGPUCODE #include +#include "ReconstructionDataFormats/TrackFwd.h" #endif using namespace o2::track; @@ -43,7 +44,7 @@ GPUd() void TrackParametrizationWithError::invert() //______________________________________________________________ template -GPUd() bool TrackParametrizationWithError::propagateTo(value_t xk, value_t b) +GPUd() bool TrackParametrizationWithError::propagateTo(value_t xk, value_t bz) { //---------------------------------------------------------------- // propagate this track to the plane X=xk (cm) in the field "b" (kG) @@ -52,7 +53,7 @@ GPUd() bool TrackParametrizationWithError::propagateTo(value_t xk, valu if (gpu::CAMath::Abs(dx) < constants::math::Almost0) { return true; } - value_t crv = this->getCurvature(b); + value_t crv = this->getCurvature(bz); value_t x2r = crv * dx; value_t f1 = this->getSnp(), f2 = f1 + x2r; if ((gpu::CAMath::Abs(f1) > constants::math::Almost1) || (gpu::CAMath::Abs(f2) > constants::math::Almost1)) { @@ -66,7 +67,8 @@ GPUd() bool TrackParametrizationWithError::propagateTo(value_t xk, valu if (gpu::CAMath::Abs(r2) < constants::math::Almost0) { return false; } - double dy2dx = (f1 + f2) / (r1 + r2); + double r1pr2Inv = 1. / (r1 + r2); + double dy2dx = (f1 + f2) * r1pr2Inv; bool arcz = gpu::CAMath::Abs(x2r) > 0.05f; params_t dP{0.f}; if (arcz) { @@ -106,14 +108,110 @@ GPUd() bool TrackParametrizationWithError::propagateTo(value_t xk, valu &c44 = mC[kSigQ2Pt2]; // evaluate matrix in double prec. - double rinv = 1. / r1; - double r3inv = rinv * rinv * rinv; - double f24 = dx * b * constants::math::B2C; // x2r/mP[kQ2Pt]; - double f02 = dx * r3inv; - double f04 = 0.5 * f24 * f02; - double f12 = f02 * this->getTgl() * f1; - double f14 = 0.5 * f24 * f12; // 0.5*f24*f02*getTgl()*f1; - double f13 = dx * rinv; + value_t kb = bz * constants::math::B2C; + double r2inv = 1. / r2, r1inv = 1. / r1; + double dx2r1pr2 = dx * r1pr2Inv; + + double hh = dx2r1pr2 * r2inv * (1. + r1 * r2 + f1 * f2), jj = dx * (dy2dx - f2 * r2inv); + double f02 = hh * r1inv; + double f04 = hh * dx2r1pr2 * kb; + double f24 = dx * kb; // x2r/mP[kQ2Pt]; + double f12 = this->getTgl() * (f02 * f2 + jj); + double f13 = dx * (r2 + f2 * dy2dx); + double f14 = this->getTgl() * (f04 * f2 + jj * f24); + + // b = C*ft + double b00 = f02 * c20 + f04 * c40, b01 = f12 * c20 + f14 * c40 + f13 * c30; + double b02 = f24 * c40; + double b10 = f02 * c21 + f04 * c41, b11 = f12 * c21 + f14 * c41 + f13 * c31; + double b12 = f24 * c41; + double b20 = f02 * c22 + f04 * c42, b21 = f12 * c22 + f14 * c42 + f13 * c32; + double b22 = f24 * c42; + double b40 = f02 * c42 + f04 * c44, b41 = f12 * c42 + f14 * c44 + f13 * c43; + double b42 = f24 * c44; + double b30 = f02 * c32 + f04 * c43, b31 = f12 * c32 + f14 * c43 + f13 * c33; + double b32 = f24 * c43; + + // a = f*b = f*C*ft + double a00 = f02 * b20 + f04 * b40, a01 = f02 * b21 + f04 * b41, a02 = f02 * b22 + f04 * b42; + double a11 = f12 * b21 + f14 * b41 + f13 * b31, a12 = f12 * b22 + f14 * b42 + f13 * b32; + double a22 = f24 * b42; + + // F*C*Ft = C + (b + bt + a) + c00 += b00 + b00 + a00; + c10 += b10 + b01 + a01; + c20 += b20 + b02 + a02; + c30 += b30; + c40 += b40; + c11 += b11 + b11 + a11; + c21 += b21 + b12 + a12; + c31 += b31; + c41 += b41; + c22 += b22 + b22 + a22; + c32 += b32; + c42 += b42; + + checkCovariance(); + + return true; +} + +//______________________________________________________________ +template +GPUd() bool TrackParametrizationWithError::propagateTo(value_t xk, TrackParametrization& linRef0, value_t bz) +{ + //---------------------------------------------------------------- + // propagate this track to the plane X=xk (cm) in the field "b" (kG), using linRef as linearization point + //---------------------------------------------------------------- + if (this->getAbsCharge() == 0) { + bz = 0; + } + value_t dx = xk - this->getX(); + if (gpu::CAMath::Abs(dx) < constants::math::Almost0) { + this->setX(xk); + linRef0.setX(xk); + return true; + } + // propagate reference track + TrackParametrization linRef1 = linRef0; + if (!linRef1.propagateTo(xk, bz)) { + return false; + } + value_t kb = bz * constants::math::B2C; + // evaluate in double prec. + double snpRef0 = linRef0.getSnp(), cspRef0 = gpu::CAMath::Sqrt((1 - snpRef0) * (1 + snpRef0)); + double snpRef1 = linRef1.getSnp(), cspRef1 = gpu::CAMath::Sqrt((1 - snpRef1) * (1 + snpRef1)); + double cspRef0Inv = 1 / cspRef0, cspRef1Inv = 1 / cspRef1, cc = cspRef0 + cspRef1, ccInv = 1 / cc, dy2dx = (snpRef0 + snpRef1) * ccInv; + double dxccInv = dx * ccInv, hh = dxccInv * cspRef1Inv * (1 + cspRef0 * cspRef1 + snpRef0 * snpRef1), jj = dx * (dy2dx - snpRef1 * cspRef1Inv); + + double f02 = hh * cspRef0Inv; + double f04 = hh * dxccInv * kb; + double f24 = dx * kb; + double f12 = linRef0.getTgl() * (f02 * snpRef1 + jj); + double f13 = dx * (cspRef1 + snpRef1 * dy2dx); // dS + double f14 = linRef0.getTgl() * (f04 * snpRef1 + jj * f24); + + // difference between the current and reference state + value_t diff[5]; + for (int i = 0; i < 5; i++) { + diff[i] = this->getParam(i) - linRef0.getParam(i); + } + value_t snpUpd = snpRef1 + diff[kSnp] + f24 * diff[kQ2Pt]; + if (gpu::CAMath::Abs(snpUpd) > constants::math::Almost1) { + return false; + } + linRef0 = linRef1; // update reference track + this->setX(xk); + this->setY(linRef1.getY() + diff[kY] + f02 * diff[kSnp] + f04 * diff[kQ2Pt]); + this->setZ(linRef1.getZ() + diff[kZ] + f13 * diff[kTgl] + f14 * diff[kQ2Pt]); + this->setSnp(snpUpd); + this->setTgl(linRef1.getTgl() + diff[kTgl]); + this->setQ2Pt(linRef1.getQ2Pt() + diff[kQ2Pt]); + + value_t &c00 = mC[kSigY2], &c10 = mC[kSigZY], &c11 = mC[kSigZ2], &c20 = mC[kSigSnpY], &c21 = mC[kSigSnpZ], + &c22 = mC[kSigSnp2], &c30 = mC[kSigTglY], &c31 = mC[kSigTglZ], &c32 = mC[kSigTglSnp], &c33 = mC[kSigTgl2], + &c40 = mC[kSigQ2PtY], &c41 = mC[kSigQ2PtZ], &c42 = mC[kSigQ2PtSnp], &c43 = mC[kSigQ2PtTgl], + &c44 = mC[kSigQ2Pt2]; // b = C*ft double b00 = f02 * c20 + f04 * c40, b01 = f12 * c20 + f14 * c40 + f13 * c30; @@ -158,6 +256,7 @@ GPUd() bool TrackParametrizationWithError::testRotate(value_t) const // no ops return true; } + //______________________________________________________________ template GPUd() bool TrackParametrizationWithError::rotate(value_t alpha) @@ -213,6 +312,101 @@ GPUd() bool TrackParametrizationWithError::rotate(value_t alpha) return true; } +//______________________________________________________________ +template +GPUd() bool TrackParametrizationWithError::rotate(value_t alpha, TrackParametrization& linRef0, value_t bz) +{ + // RS: similar to int32_t GPUTPCGMPropagator::RotateToAlpha(float newAlpha), i.e. rotate the track to new frame alpha, using linRef as linearization point + // rotate to alpha frame the reference (linearization point) trackParam, then align the current track to it + if (gpu::CAMath::Abs(this->getSnp()) > constants::math::Almost1) { + LOGP(debug, "Precondition is not satisfied: |sin(phi)|>1 ! {:f}", this->getSnp()); + return false; + } + // + math_utils::detail::bringToPMPi(alpha); + // + value_t ca = 0, sa = 0; + TrackParametrization linRef1 = linRef0; + // rotate the reference, adjusting alpha to +-pi, return precalculated cos and sin of alpha - alphaOld + if (!linRef1.rotateParam(alpha, ca, sa)) { + return false; + } + + value_t trackX = this->getX() * ca + this->getY() * sa; // X of the rotated current track + if (!linRef1.propagateParamTo(trackX, bz)) { + return false; + } + + // now rotate the current track + value_t snp = this->getSnp(), csp = gpu::CAMath::Sqrt((1.f - snp) * (1.f + snp)), updSnp = snp * ca - csp * sa; + if ((csp * ca + snp * sa) < 0 || gpu::CAMath::Abs(updSnp) > constants::math::Almost1) { + // LOGP(warning,"Rotation failed: local cos(phi) would become {:.2f}", csp * ca + snp * sa); + return false; + } + this->setY(-sa * this->getX() + ca * this->getY()); + this->setX(trackX); + this->setSnp(updSnp); + this->setAlpha(alpha); + + // rotate covariance, accounting for the extra error from the rotated X + value_t snpRef0 = linRef0.getSnp(), cspRef0 = gpu::CAMath::Sqrt((value_t(1) - snpRef0) * (value_t(1) + snpRef0)); // original reference + value_t snpRef1 = linRef1.getSnp(), cspRef1 = ca * cspRef0 + sa * snpRef0; // rotated reference + value_t rr = cspRef1 / cspRef0; // cos1_ref / cos0_ref + + // "extra row" of the lower triangle of cov. matrix + value_t cXSigY = mC[kSigY2] * ca * sa; + value_t cXSigZ = mC[kSigZY] * sa; + value_t cXSigSnp = mC[kSigSnpY] * rr * sa; + value_t cXSigTgl = mC[kSigTglY] * sa; + value_t cXSigQ2Pt = mC[kSigQ2PtY] * sa; + value_t cSigX2 = mC[kSigY2] * sa * sa; + + // plane rotation of existing cov matrix + mC[kSigY2] *= ca * ca; + mC[kSigZY] *= ca; + mC[kSigSnpY] *= ca * rr; + mC[kSigSnpZ] *= rr; + mC[kSigSnp2] *= rr * rr; + mC[kSigTglY] *= ca; + mC[kSigTglSnp] *= rr; + mC[kSigQ2PtY] *= ca; + mC[kSigQ2PtSnp] *= rr; + + // transport covariance from pseudo 6x6 matrix to usual 5x5, Jacobian (trust to Sergey): + auto cspRef1Inv = value_t(1) / cspRef1; + auto j3 = -snpRef1 * cspRef1Inv; // -pYmod/pXmod = -tg_pho = -sin_phi_mod / cos_phi_mod + auto j4 = -linRef1.getTgl() * cspRef1Inv; // -pZmod/pXmod = -tgl_mod / cos_phi_mod + auto j5 = linRef1.getCurvature(bz); + // Y Z Sin DzDs q/p X + // { { 1, 0, 0, 0, 0, j3 }, // Y + // { 0, 1, 0, 0, 0, j4 }, // Z + // { 0, 0, 1, 0, 0, j5 }, // snp + // { 0, 0, 0, 1, 0, 0 }, // tgl + // { 0, 0, 0, 0, 1, 0 } }; // q/pt + auto hXSigY = cXSigY + cSigX2 * j3; + auto hXSigZ = cXSigZ + cSigX2 * j4; + auto hXSigSnp = cXSigSnp + cSigX2 * j5; + + mC[kSigY2] += j3 * (cXSigY + hXSigY); + mC[kSigZ2] += j4 * (cXSigZ + hXSigZ); + mC[kSigSnpY] += cXSigSnp * j3 + hXSigY * j5; + mC[kSigSnp2] += j5 * (cXSigSnp + hXSigSnp); + mC[kSigTglZ] += cXSigTgl * j4; + mC[kSigQ2PtY] += cXSigQ2Pt * j3; + mC[kSigQ2PtSnp] += cXSigQ2Pt * j5; + + mC[kSigZY] += cXSigZ * j3 + hXSigY * j4; + mC[kSigSnpZ] += cXSigSnp * j4 + hXSigZ * j5; + mC[kSigTglY] += cXSigTgl * j3; + mC[kSigTglSnp] += cXSigTgl * j5; + mC[kSigQ2PtZ] += cXSigQ2Pt * j4; + + checkCovariance(); + linRef0 = linRef1; + + return true; +} + //_______________________________________________________________________ template GPUd() bool TrackParametrizationWithError::propagateToDCA(const o2::dataformats::VertexBase& vtx, value_t b, o2::dataformats::DCA* dca, value_t maxD) @@ -227,6 +421,10 @@ GPUd() bool TrackParametrizationWithError::propagateToDCA(const o2::dat // Estimate the impact parameter neglecting the track curvature value_t d = gpu::CAMath::Abs(x * snp - y * csp); if (d > maxD) { + if (dca) { // provide default DCA for failed propag + dca->set(o2::track::DefaultDCA, o2::track::DefaultDCA, + o2::track::DefaultDCACov, o2::track::DefaultDCACov, o2::track::DefaultDCACov); + } return false; } value_t crv = this->getCurvature(b); @@ -245,6 +443,10 @@ GPUd() bool TrackParametrizationWithError::propagateToDCA(const o2::dat #if !defined(GPUCA_ALIGPUCODE) LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << vtx << " | Track is: " << tmpT.asString(); #endif + if (dca) { // provide default DCA for failed propag + dca->set(o2::track::DefaultDCA, o2::track::DefaultDCA, + o2::track::DefaultDCACov, o2::track::DefaultDCACov, o2::track::DefaultDCACov); + } return false; } *this = tmpT; @@ -259,7 +461,7 @@ GPUd() bool TrackParametrizationWithError::propagateToDCA(const o2::dat //______________________________________________________________ template GPUd() TrackParametrizationWithError::TrackParametrizationWithError(const dim3_t& xyz, const dim3_t& pxpypz, - const gpu::gpustd::array& cv, int charge, bool sectorAlpha, const PID pid) + const std::array& 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); @@ -268,7 +470,7 @@ GPUd() TrackParametrizationWithError::TrackParametrizationWithError(con //______________________________________________________________ template GPUd() void TrackParametrizationWithError::set(const dim3_t& xyz, const dim3_t& pxpypz, - const gpu::gpustd::array& cv, int charge, bool sectorAlpha, const PID pid) + const std::array& cv, int charge, bool sectorAlpha, const PID pid) { // set track param and covariance from kinematics and lab errors @@ -468,14 +670,14 @@ GPUd() bool TrackParametrizationWithError::propagateTo(value_t xk, cons if (gpu::CAMath::Abs(r2) < constants::math::Almost0) { return false; } - - value_t dy2dx = (f1 + f2) / (r1 + r2); + double r1pr2Inv = 1. / (r1 + r2), r2inv = 1. / r2, r1inv = 1. / r1; + double dy2dx = (f1 + f2) * r1pr2Inv, dx2r1pr2 = dx * r1pr2Inv; 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 - gpu::gpustd::array vecLab{0.f}; + std::array vecLab{0.f}; if (!this->getPosDirGlo(vecLab)) { return false; } @@ -485,15 +687,16 @@ GPUd() bool TrackParametrizationWithError::propagateTo(value_t xk, cons &c22 = mC[kSigSnp2], &c30 = mC[kSigTglY], &c31 = mC[kSigTglZ], &c32 = mC[kSigTglSnp], &c33 = mC[kSigTgl2], &c40 = mC[kSigQ2PtY], &c41 = mC[kSigQ2PtZ], &c42 = mC[kSigQ2PtSnp], &c43 = mC[kSigQ2PtTgl], &c44 = mC[kSigQ2Pt2]; + // evaluate matrix in double prec. - double rinv = 1. / r1; - double r3inv = rinv * rinv * rinv; - double f24 = dx * b[2] * constants::math::B2C; // x2r/track[kQ2Pt]; - double f02 = dx * r3inv; - double f04 = 0.5 * f24 * f02; - double f12 = f02 * this->getTgl() * f1; - double f14 = 0.5 * f24 * f12; // 0.5*f24*f02*getTgl()*f1; - double f13 = dx * rinv; + value_t kb = b[2] * constants::math::B2C; + double hh = dx2r1pr2 * r2inv * (1. + r1 * r2 + f1 * f2), jj = dx * (dy2dx - f2 * r2inv); + double f02 = hh * r1inv; + double f04 = hh * dx2r1pr2 * kb; + double f24 = dx * kb; // x2r/mP[kQ2Pt]; + double f12 = this->getTgl() * (f02 * f2 + jj); + double f13 = dx * (r2 + f2 * dy2dx); + double f14 = this->getTgl() * (f04 * f2 + jj * f24); // b = C*ft double b00 = f02 * c20 + f04 * c40, b01 = f12 * c20 + f14 * c40 + f13 * c30; @@ -542,7 +745,7 @@ GPUd() bool TrackParametrizationWithError::propagateTo(value_t xk, cons costet = b[2] / bb; sintet = bt / bb; } - gpu::gpustd::array vect{costet * cosphi * vecLab[0] + costet * sinphi * vecLab[1] - sintet * vecLab[2], + std::array 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], @@ -574,14 +777,14 @@ GPUd() bool TrackParametrizationWithError::propagateTo(value_t xk, cons // Do the final correcting step to the target plane (linear approximation) value_t x = vecLab[0], y = vecLab[1], z = vecLab[2]; - if (gpu::CAMath::Abs(dx) > constants::math::Almost0) { + if (gpu::CAMath::Abs(x - xk) > constants::math::Almost0) { if (gpu::CAMath::Abs(vecLab[3]) < constants::math::Almost0) { return false; } - dx = xk - vecLab[0]; - x += dx; - y += vecLab[4] / vecLab[3] * dx; - z += vecLab[5] / vecLab[3] * dx; + auto dxFin = xk - vecLab[0]; + x += dxFin; + y += vecLab[4] / vecLab[3] * dxFin; + z += vecLab[5] / vecLab[3] * dxFin; } // Calculate the track parameters @@ -596,6 +799,198 @@ GPUd() bool TrackParametrizationWithError::propagateTo(value_t xk, cons return true; } +//____________________________________________________________ +template +GPUd() bool TrackParametrizationWithError::propagateTo(value_t xk, TrackParametrization& linRef0, const dim3_t& b) +{ + //---------------------------------------------------------------- + // Extrapolate this track to the plane X=xk in the field b[]. + // + // X [cm] is in the "tracking coordinate system" of this track. + // b[]={Bx,By,Bz} [kG] is in the Global coordidate system. + //---------------------------------------------------------------- + + value_t dx = xk - this->getX(); + if (gpu::CAMath::Abs(dx) < constants::math::Almost0) { + return true; + } + // Do not propagate tracks outside the ALICE detector + if (gpu::CAMath::Abs(dx) > 1e5 || gpu::CAMath::Abs(this->getY()) > 1e5 || gpu::CAMath::Abs(this->getZ()) > 1e5) { + LOG(warning) << "Anomalous track, target X:" << xk; + // print(); + return false; + } + if (gpu::CAMath::Abs(dx) < constants::math::Almost0) { + this->setX(xk); + linRef0.setX(xk); + return true; + } + // preliminary calculations to find the step size + value_t crv = (gpu::CAMath::Abs(b[2]) < constants::math::Almost0) ? 0.f : linRef0.getCurvature(b[2]); + if (gpu::CAMath::Abs(crv) < constants::math::Almost0) { + return propagateTo(xk, linRef0, 0.); + } + value_t kb = b[2] * constants::math::B2C, x2r = crv * dx; + // evaluate in double prec. + value_t snpRef0 = linRef0.getSnp(), snpRef1 = snpRef0 + x2r; + if ((gpu::CAMath::Abs(snpRef0) > constants::math::Almost1) || (gpu::CAMath::Abs(snpRef1) > constants::math::Almost1)) { + return false; + } + value_t cspRef0 = gpu::CAMath::Sqrt((1 - snpRef0) * (1 + snpRef0)), cspRef1 = gpu::CAMath::Sqrt((1 - snpRef1) * (1 + snpRef1)); + if (gpu::CAMath::Abs(cspRef0) < constants::math::Almost0 || gpu::CAMath::Abs(cspRef1) < constants::math::Almost0) { + return false; + } + value_t cspRef0Inv = value_t(1) / cspRef0, cspRef1Inv = value_t(1) / cspRef1, cc = cspRef0 + cspRef1, ccInv = value_t(1) / cc, dy2dx = (snpRef0 + snpRef1) * ccInv; + value_t step = (gpu::CAMath::Abs(crv * dx) < 0.05f) ? dx * (cspRef1 + snpRef1 * dy2dx) : 2. * gpu::CAMath::ASin(0.5 * dx * gpu::CAMath::Sqrt(1.f + dy2dx * dy2dx) * crv) / crv; // arc + step *= gpu::CAMath::Sqrt(1.f + linRef0.getTgl() * linRef0.getTgl()); + + // + // get the track x,y,z,px/p,py/p,pz/p,p,sinAlpha,cosAlpha in the Global System + std::array vecLab{0.f}; + if (!linRef0.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 = 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 = 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 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 = this->getCharge(); + g3helx3(q * bb, step, vect); + + // Rotate back to the Global System + vecLab[0] = cosphi * costet * vect[0] - sinphi * vect[1] + cosphi * sintet * vect[2]; + vecLab[1] = sinphi * costet * vect[0] + cosphi * vect[1] + sinphi * sintet * vect[2]; + vecLab[2] = -sintet * vect[0] + costet * vect[2]; + + vecLab[3] = cosphi * costet * vect[3] - sinphi * vect[4] + cosphi * sintet * vect[5]; + vecLab[4] = sinphi * costet * vect[3] + cosphi * vect[4] + sinphi * sintet * vect[5]; + vecLab[5] = -sintet * vect[3] + costet * vect[5]; + + // Rotate back to the Tracking System + value_t sinalp = -vecLab[7], cosalp = vecLab[8]; + value_t t = cosalp * vecLab[0] - sinalp * vecLab[1]; + vecLab[1] = sinalp * vecLab[0] + cosalp * vecLab[1]; + vecLab[0] = t; + t = cosalp * vecLab[3] - sinalp * vecLab[4]; + vecLab[4] = sinalp * vecLab[3] + cosalp * vecLab[4]; + vecLab[3] = t; + + // Do the final correcting step to the target plane (linear approximation) + value_t x = vecLab[0], y = vecLab[1], z = vecLab[2]; + if (gpu::CAMath::Abs(x - xk) > constants::math::Almost0) { + if (gpu::CAMath::Abs(vecLab[3]) < constants::math::Almost0) { + return false; + } + auto dxFin = xk - vecLab[0]; + x += dxFin; + y += vecLab[4] / vecLab[3] * dxFin; + z += vecLab[5] / vecLab[3] * dxFin; + } + + // Calculate the track parameters + auto linRef1 = linRef0; + t = 1.f / gpu::CAMath::Sqrt(vecLab[3] * vecLab[3] + vecLab[4] * vecLab[4]); + linRef1.setX(xk); + linRef1.setY(y); + linRef1.setZ(z); + linRef1.setSnp(snpRef1 = vecLab[4] * t); // reassign snpRef1 + linRef1.setTgl(vecLab[5] * t); + linRef1.setQ2Pt(q * t / vecLab[6]); + + // recalculate parameters of the transported ref track needed for transport of this: + cspRef1 = gpu::CAMath::Sqrt((1 - snpRef1) * (1 + snpRef1)); + cspRef1Inv = value_t(1) / cspRef1; + cc = cspRef0 + cspRef1; + ccInv = value_t(1) / cc; + dy2dx = (snpRef0 + snpRef1) * ccInv; + double dxccInv = dx * ccInv, hh = dxccInv * cspRef1Inv * (1 + cspRef0 * cspRef1 + snpRef0 * snpRef1), jj = dx * (dy2dx - snpRef1 * cspRef1Inv); + double f02 = hh * cspRef0Inv; + double f04 = hh * dxccInv * kb; + double f24 = dx * kb; + double f12 = linRef0.getTgl() * (f02 * snpRef1 + jj); + double f13 = dx * (cspRef1 + snpRef1 * dy2dx); // dS + double f14 = linRef0.getTgl() * (f04 * snpRef1 + jj * f24); + + // difference between the current and reference state + value_t diff[5]; + for (int i = 0; i < 5; i++) { + diff[i] = this->getParam(i) - linRef0.getParam(i); + } + value_t snpUpd = snpRef1 + diff[kSnp] + f24 * diff[kQ2Pt]; + if (gpu::CAMath::Abs(snpUpd) > constants::math::Almost1) { + return false; + } + this->setX(xk); + this->setY(linRef1.getY() + diff[kY] + f02 * diff[kSnp] + f04 * diff[kQ2Pt]); + this->setZ(linRef1.getZ() + diff[kZ] + f13 * diff[kTgl] + f14 * diff[kQ2Pt]); + this->setSnp(snpUpd); + this->setTgl(linRef1.getTgl() + diff[kTgl]); + this->setQ2Pt(linRef1.getQ2Pt() + diff[kQ2Pt]); + + linRef0 = linRef1; // update reference track + + // matrix transformed with Bz component only + value_t &c00 = mC[kSigY2], &c10 = mC[kSigZY], &c11 = mC[kSigZ2], &c20 = mC[kSigSnpY], &c21 = mC[kSigSnpZ], + &c22 = mC[kSigSnp2], &c30 = mC[kSigTglY], &c31 = mC[kSigTglZ], &c32 = mC[kSigTglSnp], &c33 = mC[kSigTgl2], + &c40 = mC[kSigQ2PtY], &c41 = mC[kSigQ2PtZ], &c42 = mC[kSigQ2PtSnp], &c43 = mC[kSigQ2PtTgl], + &c44 = mC[kSigQ2Pt2]; + + // b = C*ft + double b00 = f02 * c20 + f04 * c40, b01 = f12 * c20 + f14 * c40 + f13 * c30; + double b02 = f24 * c40; + double b10 = f02 * c21 + f04 * c41, b11 = f12 * c21 + f14 * c41 + f13 * c31; + double b12 = f24 * c41; + double b20 = f02 * c22 + f04 * c42, b21 = f12 * c22 + f14 * c42 + f13 * c32; + double b22 = f24 * c42; + double b40 = f02 * c42 + f04 * c44, b41 = f12 * c42 + f14 * c44 + f13 * c43; + double b42 = f24 * c44; + double b30 = f02 * c32 + f04 * c43, b31 = f12 * c32 + f14 * c43 + f13 * c33; + double b32 = f24 * c43; + + // a = f*b = f*C*ft + double a00 = f02 * b20 + f04 * b40, a01 = f02 * b21 + f04 * b41, a02 = f02 * b22 + f04 * b42; + double a11 = f12 * b21 + f14 * b41 + f13 * b31, a12 = f12 * b22 + f14 * b42 + f13 * b32; + double a22 = f24 * b42; + + // F*C*Ft = C + (b + bt + a) + c00 += b00 + b00 + a00; + c10 += b10 + b01 + a01; + c20 += b20 + b02 + a02; + c30 += b30; + c40 += b40; + c11 += b11 + b11 + a11; + c21 += b21 + b12 + a12; + c31 += b31; + c41 += b41; + c22 += b22 + b22 + a22; + c32 += b32; + c42 += b42; + + checkCovariance(); + + return true; +} + //______________________________________________ template GPUd() void TrackParametrizationWithError::checkCorrelations() @@ -1113,9 +1508,146 @@ GPUd() bool TrackParametrizationWithError::correctForMaterial(value_t x return true; } +//______________________________________________ +template +GPUd() bool TrackParametrizationWithError::correctForMaterial(TrackParametrization& linRef, value_t x2x0, value_t xrho, bool anglecorr) +{ + //------------------------------------------------------------------ + // This function corrects the reference and current track parameters for the crossed material + // "x2x0" - X/X0, the thickness in units of the radiation length. + // "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. + // "dedx" - mean enery loss (GeV/(g/cm^2), if <=kCalcdEdxAuto : calculate on the fly + // "anglecorr" - switch for the angular correction + //------------------------------------------------------------------ + constexpr value_t kMSConst2 = 0.0136f * 0.0136f; + constexpr value_t kMinP = 0.01f; // kill below this momentum + + value_t csp2 = (1.f - linRef.getSnp()) * (1.f + linRef.getSnp()); // cos(phi)^2 + value_t cst2I = (1.f + linRef.getTgl() * linRef.getTgl()); // 1/cos(lambda)^2 + if (anglecorr) { // Apply angle correction, if requested + value_t angle = gpu::CAMath::Sqrt(cst2I / csp2); + x2x0 *= angle; + xrho *= angle; + } + auto pid = linRef.getPID(); + auto m = pid.getMass(); + int charge2 = linRef.getAbsCharge() * linRef.getAbsCharge(); + value_t p = linRef.getP(), p0 = p, p02 = p * p, e2 = p02 + pid.getMass2(), massInv = 1. / m, bg = p * massInv, dETot = 0.; + value_t e = gpu::CAMath::Sqrt(e2), e0 = e; + if (m > 0 && xrho != 0.f) { + value_t ekin = e - m, dedx = this->getdEdxBBOpt(bg); +#ifdef _BB_NONCONST_CORR_ + value_t dedxDer = 0., dedx1 = dedx; +#endif + if (charge2 != 1) { + dedx *= charge2; + } + value_t dE = dedx * xrho; + int na = 1 + int(gpu::CAMath::Abs(dE) / ekin * ELoss2EKinThreshInv); + if (na > MaxELossIter) { + na = MaxELossIter; + } + if (na > 1) { + dE /= na; + xrho /= na; +#ifdef _BB_NONCONST_CORR_ + dedxDer = this->getBetheBlochSolidDerivativeApprox(dedx1, bg); // require correction for non-constantness of dedx vs betagamma + if (charge2 != 1) { + dedxDer *= charge2; + } +#endif + } + while (na--) { +#ifdef _BB_NONCONST_CORR_ + if (dedxDer != 0.) { // correction for non-constantness of dedx vs beta*gamma (in linear approximation): for a single step dE -> dE * [(exp(dedxDer) - 1)/dedxDer] + if (xrho < 0) { + dedxDer = -dedxDer; // E.loss ( -> positive derivative) + } + auto corrC = (gpu::CAMath::Exp(dedxDer) - 1.) / dedxDer; + dE *= corrC; + } +#endif + e += dE; + if (e > m) { // stopped + p = gpu::CAMath::Sqrt(e * e - pid.getMass2()); + } else { + return false; + } + if (na) { + bg = p * massInv; + dedx = this->getdEdxBBOpt(bg); +#ifdef _BB_NONCONST_CORR_ + dedxDer = this->getBetheBlochSolidDerivativeApprox(dedx, bg); +#endif + if (charge2 != 1) { + dedx *= charge2; +#ifdef _BB_NONCONST_CORR_ + dedxDer *= charge2; +#endif + } + dE = dedx * xrho; + } + } + + if (p < kMinP) { + return false; + } + dETot = e - e0; + } // end of e.loss correction + + // Calculating the multiple scattering corrections****************** + value_t& fC22 = mC[kSigSnp2]; + value_t& fC33 = mC[kSigTgl2]; + value_t& fC43 = mC[kSigQ2PtTgl]; + value_t& fC44 = mC[kSigQ2Pt2]; + // + value_t cC22(0.f), cC33(0.f), cC43(0.f), cC44(0.f); + if (x2x0 != 0.f) { + value_t beta2 = p02 / e2, theta2 = kMSConst2 / (beta2 * p02) * gpu::CAMath::Abs(x2x0); + value_t fp34 = linRef.getTgl(); + if (charge2 != 1) { + theta2 *= charge2; + fp34 *= linRef.getCharge2Pt(); + } + if (theta2 > constants::math::PI * constants::math::PI) { + return false; + } + value_t t2c2I = theta2 * cst2I; + cC22 = t2c2I * csp2; + cC33 = t2c2I * cst2I; + cC43 = t2c2I * fp34; + cC44 = theta2 * fp34 * fp34; + // optimize this + // cC22 = theta2*((1.-getSnp())*(1.+getSnp()))*(1. + this->getTgl()*getTgl()); + // cC33 = theta2*(1. + this->getTgl()*getTgl())*(1. + this->getTgl()*getTgl()); + // cC43 = theta2*getTgl()*this->getQ2Pt()*(1. + this->getTgl()*getTgl()); + // cC44 = theta2*getTgl()*this->getQ2Pt()*getTgl()*this->getQ2Pt(); + } + + // the energy loss correction contribution to cov.matrix: approximate energy loss fluctuation (M.Ivanov) + constexpr value_t knst = 0.0007f; // To be tuned. + value_t sigmadE = knst * gpu::CAMath::Sqrt(gpu::CAMath::Abs(dETot)) * e0 / p02 * linRef.getCharge2Pt(); + cC44 += sigmadE * sigmadE; + + // Applying the corrections***************************** + fC22 += cC22; + fC33 += cC33; + fC43 += cC43; + fC44 += cC44; + auto pscale = p0 / p; + linRef.setQ2Pt(linRef.getQ2Pt() * pscale); + this->setQ2Pt(this->getQ2Pt() * pscale); + + checkCovariance(); + + return true; +} + //______________________________________________________________ template -GPUd() bool TrackParametrizationWithError::getCovXYZPxPyPzGlo(gpu::gpustd::array& cv) const +GPUd() bool TrackParametrizationWithError::getCovXYZPxPyPzGlo(std::array& cv) const { //--------------------------------------------------------------------- // This function returns the global covariance matrix of the track params @@ -1237,6 +1769,64 @@ GPUd() void TrackParametrizationWithError::printHexadecimal() #endif } +#ifndef GPUCA_ALIGPUCODE +//______________________________________________________________ +template +bool TrackParametrizationWithError::toFwdTrackParCov(TrackParCovFwd& t) const +{ + auto p = this->getXYZGlo(); + t.setZ(p.Z()); + t.setX(p.X()); + t.setY(p.Y()); + t.setPhi(this->getPhi()); + t.setTanl(this->getTgl()); + t.setInvQPt(this->getQ2Pt()); + // + if (gpu::CAMath::Abs(this->getSnp()) >= o2::constants::math::Almost1 || + gpu::CAMath::Abs(this->getTgl()) <= o2::constants::math::Almost0) { + return false; + } + value_T csa, sna, csP, snP, csp = gpu::CAMath::Sqrt((1. - this->getSnp()) * (1. + this->getSnp())); + math_utils::detail::sincos(value_T(this->getAlpha()), sna, csa); + math_utils::detail::sincos(value_T(t.getPhi()), snP, csP); + /* + Jacobian is + /-sna -csP/tgL 0 0 0 \ + | csa -snP/tgL 0 0 0 | + | 0 0 1/csp 0 0 | + | 0 0 0 1 0 | + \ 0 0 0 0 1 / + */ + auto tgLI = 1 / this->getTgl(); + const value_T d1 = -sna; + const value_T d2 = -csP * tgLI; + const value_T e1 = csa; + const value_T e2 = -snP * tgLI; + const value_T f1 = 1 / csp; + SMatrix55Sym C; + C(0, 0) = d1 * d1 * getSigmaY2() + 2 * d1 * d2 * getSigmaZY() + d2 * d2 * getSigmaZ2(); + C(0, 1) = d1 * e1 * getSigmaY2() + (d1 * e2 + d2 * e1) * getSigmaZY() + d2 * e2 * getSigmaZ2(); + C(1, 1) = e1 * e1 * getSigmaY2() + 2 * e1 * e2 * getSigmaZY() + e2 * e2 * getSigmaZ2(); + + C(0, 2) = f1 * (d1 * getSigmaSnpY() + d2 * getSigmaSnpZ()); + C(1, 2) = f1 * (e1 * getSigmaSnpY() + e2 * getSigmaSnpZ()); + C(2, 2) = f1 * f1 * getSigmaSnp2(); + + C(0, 3) = d1 * getSigmaTglY() + d2 * getSigmaTglZ(); + C(1, 3) = e1 * getSigmaTglY() + e2 * getSigmaTglZ(); + C(2, 3) = f1 * getSigmaTglSnp(); + C(3, 3) = getSigmaTgl2(); + + C(0, 4) = d1 * getSigma1PtY() + d2 * getSigma1PtZ(); + C(1, 4) = e1 * getSigma1PtY() + e2 * getSigma1PtZ(); + C(2, 4) = f1 * getSigma1PtSnp(); + C(3, 4) = getSigma1PtTgl(); + C(4, 4) = getSigma1Pt2(); + t.setCovariances(C); + return true; +} +#endif + namespace o2::track { #if !defined(GPUCA_GPUCODE) || defined(GPUCA_GPUCODE_DEVICE) // FIXME: DR: WORKAROUND to avoid CUDA bug creating host symbols for device code. diff --git a/DataFormats/Reconstruction/src/Vertex.cxx b/DataFormats/Reconstruction/src/Vertex.cxx index b902e9972a13d..9294aeb655803 100644 --- a/DataFormats/Reconstruction/src/Vertex.cxx +++ b/DataFormats/Reconstruction/src/Vertex.cxx @@ -10,9 +10,9 @@ // or submit itself to any jurisdiction. #include "ReconstructionDataFormats/Vertex.h" -#include #ifndef GPUCA_NO_FMT -#include +#include +#include #endif namespace o2 @@ -20,8 +20,6 @@ namespace o2 namespace dataformats { -#ifndef GPUCA_GPUCODE_DEVICE -#ifndef GPUCA_NO_FMT std::string VertexBase::asString() const { return fmt::format("Vtx {{{:+.4e},{:+.4e},{:+.4e}}} Cov.:{{{{{:.3e}..}},{{{:.3e},{:.3e}..}},{{{:.3e},{:.3e},{:.3e}}}}}", @@ -39,7 +37,6 @@ void VertexBase::print() const { std::cout << *this << std::endl; } -#endif bool VertexBase::operator==(const VertexBase& other) const { @@ -54,8 +51,6 @@ bool VertexBase::operator==(const VertexBase& other) const return true; } -#endif - template class o2::dataformats::Vertex>; template class o2::dataformats::Vertex>; diff --git a/DataFormats/common/include/CommonDataFormat/AbstractRef.h b/DataFormats/common/include/CommonDataFormat/AbstractRef.h index 403bab3cbd62f..72c195cfb7bc8 100644 --- a/DataFormats/common/include/CommonDataFormat/AbstractRef.h +++ b/DataFormats/common/include/CommonDataFormat/AbstractRef.h @@ -18,7 +18,10 @@ #include "GPUCommonDef.h" #include "GPUCommonRtypes.h" -#include "GPUCommonTypeTraits.h" +#ifndef GPUCA_GPUCODE_DEVICE +#include +#endif + namespace o2::dataformats { diff --git a/DataFormats/common/include/CommonDataFormat/BunchFilling.h b/DataFormats/common/include/CommonDataFormat/BunchFilling.h index 182a665532668..f11ce2498d04b 100644 --- a/DataFormats/common/include/CommonDataFormat/BunchFilling.h +++ b/DataFormats/common/include/CommonDataFormat/BunchFilling.h @@ -107,7 +107,6 @@ class BunchFilling ClassDefNV(BunchFilling, 2); }; -} // namespace o2 namespace framework { @@ -118,5 +117,6 @@ struct is_messageable : std::true_type { }; } // namespace framework +} // namespace o2 #endif diff --git a/DataFormats/common/include/CommonDataFormat/InteractionRecord.h b/DataFormats/common/include/CommonDataFormat/InteractionRecord.h index 7aa3ccdd5d12c..c22b24ad03aac 100644 --- a/DataFormats/common/include/CommonDataFormat/InteractionRecord.h +++ b/DataFormats/common/include/CommonDataFormat/InteractionRecord.h @@ -15,7 +15,7 @@ #define ALICEO2_INTERACTIONRECORD_H #include "GPUCommonRtypes.h" -#ifndef GPUCA_ALIGPUCODE +#ifndef GPUCA_GPUCODE_DEVICE #include #include #endif @@ -281,7 +281,7 @@ struct InteractionRecord { return tmp; } -#ifndef GPUCA_ALIGPUCODE +#if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE) void print() const; std::string asString() const; friend std::ostream& operator<<(std::ostream& stream, InteractionRecord const& ir); @@ -359,7 +359,7 @@ struct InteractionTimeRecord : public InteractionRecord { return !((*this) > other); } -#ifndef GPUCA_ALIGPUCODE +#if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE) void print() const; std::string asString() const; friend std::ostream& operator<<(std::ostream& stream, InteractionTimeRecord const& ir); diff --git a/DataFormats/common/include/CommonDataFormat/RangeReference.h b/DataFormats/common/include/CommonDataFormat/RangeReference.h index 0308d3b8af937..3d0c58298de03 100644 --- a/DataFormats/common/include/CommonDataFormat/RangeReference.h +++ b/DataFormats/common/include/CommonDataFormat/RangeReference.h @@ -29,23 +29,23 @@ template class RangeReference { public: - GPUd() RangeReference(FirstEntry ent, NElem n) { set(ent, n); } - GPUdDefault() RangeReference(const RangeReference& src) = default; - GPUdDefault() RangeReference() = default; - GPUdDefault() ~RangeReference() = default; - GPUd() void set(FirstEntry ent, NElem n) + GPUhd() RangeReference(FirstEntry ent, NElem n) { set(ent, n); } + GPUhdDefault() RangeReference(const RangeReference& src) = default; + GPUhdDefault() RangeReference() = default; + GPUhdDefault() ~RangeReference() = default; + GPUhd() void set(FirstEntry ent, NElem n) { mFirstEntry = ent; mEntries = n; } - 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 + GPUhd() void clear() { set(0, 0); } + GPUhd() FirstEntry getFirstEntry() const { return mFirstEntry; } + GPUhd() FirstEntry getEntriesBound() const { return mFirstEntry + mEntries; } + GPUhd() NElem getEntries() const { return mEntries; } + GPUhd() void setFirstEntry(FirstEntry ent) { mFirstEntry = ent; } + GPUhd() void setEntries(NElem n) { mEntries = n; } + GPUhd() void changeEntriesBy(NElem inc) { mEntries += inc; } + GPUhd() bool operator==(const RangeReference& other) const { return mFirstEntry == other.mFirstEntry && mEntries == other.mEntries; } @@ -68,21 +68,21 @@ class RangeRefComp static constexpr Base MaskN = ((0x1 << NBitsN) - 1); static constexpr Base MaskR = (~Base(0)) & (~MaskN); Base mData = 0; ///< packed 1st entry reference + N entries - GPUd() void sanityCheck() + GPUhd() void sanityCheck() { static_assert(NBitsN < NBitsTotal, "NBitsN too large"); } public: - GPUd() RangeRefComp(int ent, int n) { set(ent, n); } - GPUdDefault() RangeRefComp() = default; - GPUdDefault() RangeRefComp(const RangeRefComp& src) = default; + GPUhd() RangeRefComp(int ent, int n) { set(ent, n); } + GPUhdDefault() RangeRefComp() = default; + GPUhdDefault() RangeRefComp(const RangeRefComp& src) = default; GPUhd() void set(int ent, int n) { mData = (Base(ent) << NBitsN) + (Base(n) & MaskN); } - GPUd() static constexpr Base getMaxFirstEntry() { return MaskR >> NBitsN; } - GPUd() static constexpr Base getMaxEntries() { return MaskN; } + GPUhd() static constexpr Base getMaxFirstEntry() { return MaskR >> NBitsN; } + GPUhd() 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(); } diff --git a/DataFormats/common/include/CommonDataFormat/TFIDInfo.h b/DataFormats/common/include/CommonDataFormat/TFIDInfo.h index 2a41a4e725781..9628b38b95fa3 100644 --- a/DataFormats/common/include/CommonDataFormat/TFIDInfo.h +++ b/DataFormats/common/include/CommonDataFormat/TFIDInfo.h @@ -29,6 +29,7 @@ struct TFIDInfo { // helper info to patch DataHeader uint32_t runNumber = -1U; uint32_t startTime = -1U; // same as timeslot uint64_t creation = -1UL; + bool discard = false; bool isDummy() { return tfCounter == -1U; } void fill(uint32_t firstTForbit_, uint32_t tfCounter_, uint32_t runNumber_, uint32_t startTime_, uint64_t creation_) @@ -38,9 +39,10 @@ struct TFIDInfo { // helper info to patch DataHeader runNumber = runNumber_; startTime = startTime_; creation = creation_; + discard = (firstTForbit < tfCounter) || firstTForbit == -1U || creation == -1; } - ClassDefNV(TFIDInfo, 2); + ClassDefNV(TFIDInfo, 3); }; } // namespace dataformats } // namespace o2 diff --git a/DataFormats/common/include/CommonDataFormat/TimeStamp.h b/DataFormats/common/include/CommonDataFormat/TimeStamp.h index 56a71414c6b86..709af221c28f8 100644 --- a/DataFormats/common/include/CommonDataFormat/TimeStamp.h +++ b/DataFormats/common/include/CommonDataFormat/TimeStamp.h @@ -27,10 +27,10 @@ class TimeStamp public: GPUhdDefault() TimeStamp() = default; GPUhdDefault() ~TimeStamp() = default; - GPUdi() TimeStamp(T time) { mTimeStamp = time; } + GPUhdi() TimeStamp(T time) { mTimeStamp = time; } GPUhdi() T getTimeStamp() const { return mTimeStamp; } - GPUdi() void setTimeStamp(T t) { mTimeStamp = t; } - GPUdi() bool operator==(const TimeStamp& t) const { return mTimeStamp == t.mTimeStamp; } + GPUhdi() void setTimeStamp(T t) { mTimeStamp = t; } + GPUhdi() bool operator==(const TimeStamp& t) const { return mTimeStamp == t.mTimeStamp; } private: T mTimeStamp = 0; @@ -41,11 +41,11 @@ template class TimeStampWithError : public TimeStamp { public: - GPUdDefault() TimeStampWithError() = default; - GPUd() TimeStampWithError(T t, E te) : TimeStamp(t), mTimeStampError(te) {} - GPUdi() E getTimeStampError() const { return mTimeStampError; } - GPUdi() E getTimeStampError2() const { return mTimeStampError * mTimeStampError; } - GPUdi() void setTimeStampError(E te) { mTimeStampError = te; } + GPUhdDefault() TimeStampWithError() = default; + GPUhd() TimeStampWithError(T t, E te) : TimeStamp(t), mTimeStampError(te) {} + GPUhdi() E getTimeStampError() const { return mTimeStampError; } + GPUhdi() E getTimeStampError2() const { return mTimeStampError * mTimeStampError; } + GPUhdi() void setTimeStampError(E te) { mTimeStampError = te; } private: E mTimeStampError = 0; diff --git a/DataFormats/common/src/CommonDataFormatLinkDef.h b/DataFormats/common/src/CommonDataFormatLinkDef.h index 631305cd28f13..d66e89af637cc 100644 --- a/DataFormats/common/src/CommonDataFormatLinkDef.h +++ b/DataFormats/common/src/CommonDataFormatLinkDef.h @@ -26,10 +26,12 @@ #pragma link C++ class o2::dataformats::TimeStamp < float> + ; #pragma link C++ class o2::dataformats::TimeStamp < double> + ; #pragma link C++ class o2::dataformats::TimeStamp < int> + ; -#pragma link C++ class o2::dataformats::TimeStamp < Float16_t > + ; +#pragma link C++ class o2::dataformats::TimeStamp < uint32_t> + ; +#pragma link C++ class o2::dataformats::TimeStamp < Float16_t> + ; #pragma link C++ class o2::dataformats::TimeStampWithError < float, float> + ; #pragma link C++ class o2::dataformats::TimeStampWithError < double, double> + ; #pragma link C++ class o2::dataformats::TimeStampWithError < int, int> + ; +#pragma link C++ class o2::dataformats::TimeStampWithError < uint32_t, uint16_t> + ; #pragma link C++ class o2::dataformats::EvIndex < int, int> + ; #pragma link C++ class o2::dataformats::RangeReference < int, int> + ; diff --git a/DataFormats/common/src/InteractionRecord.cxx b/DataFormats/common/src/InteractionRecord.cxx index f15c8c8e85328..213ed600e1c57 100644 --- a/DataFormats/common/src/InteractionRecord.cxx +++ b/DataFormats/common/src/InteractionRecord.cxx @@ -15,8 +15,6 @@ namespace o2 { -#ifndef GPUCA_ALIGPUCODE - std::string InteractionRecord::asString() const { return isDummy() ? std::string{"NotSet"} : fmt::format("BCid: {:4d} Orbit: {:6d}", bc, orbit); @@ -49,6 +47,4 @@ void InteractionTimeRecord::print() const std::cout << (*this) << std::endl; } -#endif - } // namespace o2 diff --git a/DataFormats/simulation/CMakeLists.txt b/DataFormats/simulation/CMakeLists.txt index fac67cc927562..33c91337c77e9 100644 --- a/DataFormats/simulation/CMakeLists.txt +++ b/DataFormats/simulation/CMakeLists.txt @@ -55,6 +55,11 @@ o2_target_root_dictionary( # * src/SimulationDataLinkDef.h # * and not src/SimulationDataFormatLinkDef.h +o2_add_test(InteractionSampler + SOURCES test/testInteractionSampler.cxx + COMPONENT_NAME SimulationDataFormat + PUBLIC_LINK_LIBRARIES O2::SimulationDataFormat) + o2_add_test(BasicHits SOURCES test/testBasicHits.cxx COMPONENT_NAME SimulationDataFormat diff --git a/DataFormats/simulation/include/SimulationDataFormat/BaseHits.h b/DataFormats/simulation/include/SimulationDataFormat/BaseHits.h index b9ed356ec8b5a..d1e1ee357c1cf 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/BaseHits.h +++ b/DataFormats/simulation/include/SimulationDataFormat/BaseHits.h @@ -49,13 +49,13 @@ class BasicXYZVHit : public BaseHit math_utils::Point3D mPos; // cartesian position of Hit E mTime; // time of flight V mHitValue; // hit value - short mDetectorID; // the detector/sensor id + unsigned short mDetectorID; // the detector/sensor id public: BasicXYZVHit() = default; // for ROOT IO // constructor - BasicXYZVHit(T x, T y, T z, E time, V val, int trackid, short did) + BasicXYZVHit(T x, T y, T z, E time, V val, int trackid, unsigned short did) : mPos(x, y, z), mTime(time), mHitValue(val), BaseHit(trackid), mDetectorID(did) { } @@ -70,12 +70,12 @@ class BasicXYZVHit : public BaseHit // getting the time E GetTime() const { return mTime; } // get detector + track information - short GetDetectorID() const { return mDetectorID; } + unsigned short GetDetectorID() const { return mDetectorID; } // modifiers void SetTime(E time) { mTime = time; } void SetHitValue(V val) { mHitValue = val; } - void SetDetectorID(short detID) { mDetectorID = detID; } + void SetDetectorID(unsigned short detID) { mDetectorID = detID; } void SetX(T x) { mPos.SetX(x); } void SetY(T y) { mPos.SetY(y); } void SetZ(T z) { mPos.SetZ(z); } @@ -87,7 +87,7 @@ class BasicXYZVHit : public BaseHit } void SetPos(math_utils::Point3D const& p) { mPos = p; } - ClassDefNV(BasicXYZVHit, 1); + ClassDefNV(BasicXYZVHit, 2); }; // Class for a hit containing energy loss as hit value diff --git a/DataFormats/simulation/include/SimulationDataFormat/DigitizationContext.h b/DataFormats/simulation/include/SimulationDataFormat/DigitizationContext.h index b718b2d5eb804..0dc3806e52cf2 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/DigitizationContext.h +++ b/DataFormats/simulation/include/SimulationDataFormat/DigitizationContext.h @@ -141,6 +141,12 @@ class DigitizationContext // have to have same vertex, as well as event ids associated to same collision. void sampleInteractionVertices(o2::dataformats::MeanVertexObject const& v); + // Function allowing to inject interaction vertixes from the outside. + // Useful when this is given from data for instance. The vertex vector needs to be of same + // size as the interaction record. + // Returns 0 if success. 1 if there is a problem. + int setInteractionVertices(std::vector> const& vertices); + // helper functions to save and load a context void saveToFile(std::string_view filename) const; diff --git a/DataFormats/simulation/include/SimulationDataFormat/InteractionSampler.h b/DataFormats/simulation/include/SimulationDataFormat/InteractionSampler.h index 13fe099aa344a..47dd4f5e4652d 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/InteractionSampler.h +++ b/DataFormats/simulation/include/SimulationDataFormat/InteractionSampler.h @@ -22,6 +22,7 @@ #include "CommonDataFormat/BunchFilling.h" #include "CommonConstants/LHCConstants.h" #include "MathUtils/RandomRing.h" +#include namespace o2 { @@ -67,7 +68,7 @@ class InteractionSampler void print() const; protected: - int simulateInteractingBC(); + virtual int simulateInteractingBC(); void nextCollidingBC(int n); o2::math_utils::RandomRing<10000> mBCJumpGenerator; // generator of random jumps in BC @@ -89,7 +90,7 @@ class InteractionSampler static constexpr float DefIntRate = 50e3; ///< default interaction rate - ClassDefNV(InteractionSampler, 1); + ClassDef(InteractionSampler, 1); }; //_________________________________________________ @@ -113,6 +114,47 @@ inline void InteractionSampler::nextCollidingBC(int n) mIR.bc = mInteractingBCs[mCurrBCIdx]; } +// Special case of InteractionSampler without actual sampling. +// Engineers interaction sequence by putting one in each N-th BC with multiplicity mult. +class FixedSkipBC_InteractionSampler : public InteractionSampler +{ + + public: + FixedSkipBC_InteractionSampler(int every_n, int mult) : mEveryN{every_n}, mMultiplicity{mult}, InteractionSampler() {} + + protected: + int simulateInteractingBC() override; + + private: + int mEveryN; // the skip number ---> fills every N-th BC in the bunch filling scheme + int mMultiplicity; // how many events to put if bc is filled + ClassDef(FixedSkipBC_InteractionSampler, 1); +}; + +// A version of the interaction sampler which can sample according to non-uniform mu(bc) as +// observed during data taking. +class NonUniformMuInteractionSampler : public InteractionSampler +{ + public: + NonUniformMuInteractionSampler() : InteractionSampler() { mBCIntensityScales.resize(o2::constants::lhc::LHCMaxBunches, 1); } + bool setBCIntensityScales(const std::vector& scales_from_vector); + bool setBCIntensityScales(const TH1F& scales_from_histo); // initialize scales + + // helper function to determine the scales from a histogram (count from event selection analysis) + std::vector determineBCIntensityScalesFromHistogram(const TH1F& scales_from_histo); + + const std::vector& getBCIntensityScales() const { return mBCIntensityScales; } + + protected: + int simulateInteractingBC() override; + int getBCJump() const; + + private: + // non-uniformity + std::vector mBCIntensityScales; + ClassDef(NonUniformMuInteractionSampler, 1); +}; + } // namespace steer } // namespace o2 diff --git a/DataFormats/simulation/include/SimulationDataFormat/O2DatabasePDG.h b/DataFormats/simulation/include/SimulationDataFormat/O2DatabasePDG.h index 0ee5c06a74411..ef259e5322bb8 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/O2DatabasePDG.h +++ b/DataFormats/simulation/include/SimulationDataFormat/O2DatabasePDG.h @@ -470,6 +470,15 @@ inline void O2DatabasePDG::addALICEParticles(TDatabasePDG* db) 0.185, 0, "Resonance", ionCode); } + // Lambda(1405)0 + ionCode = 102132; + if (!db->GetParticle(ionCode)) { + db->AddParticle("Lambda_1405_0", "Lambda_1405_0", 1.405, kFALSE, 0.05, 0, "Resonance", ionCode); + } + if (!db->GetParticle(-ionCode)) { + db->AddParticle("AntiLambda_1405_0", "AntiLambda_1405_0", 1.405, kFALSE, 0.05, 0, "Resonance", -ionCode); + } + // Lambda(1520)0 ionCode = 102134; if (!db->GetParticle(ionCode)) { @@ -515,6 +524,48 @@ inline void O2DatabasePDG::addALICEParticles(TDatabasePDG* db) db->AddParticle("f2_1525", "f2_1525", 1.525, kFALSE, 0.073, 0, "Resonance", ionCode); } + // when using hadronic rescattering in Pythia8 + ionCode = 9000221; + if (!db->GetParticle(ionCode)) { + db->AddParticle("f0_500", "f0_500", 0.500, kFALSE, 0.350, 0.0, "Resonance", ionCode); + } + ionCode = -100313; + if (!db->GetParticle(ionCode)) { + db->AddParticle("K*(1410)bar0", "K*(1410)bar0", 1.414, kFALSE, 0.232, 0, "Resonance", ionCode); + } + ionCode = 100313; + if (!db->GetParticle(ionCode)) { + db->AddParticle("K*(1410)0", "K*(1410)0", 1.414, kFALSE, 0.232, 0, "Resonance", ionCode); + } + ionCode = 100323; + if (!db->GetParticle(ionCode)) { + db->AddParticle("K*(1410)+", "K*(1410)+", 1.414, kFALSE, 0.232, +1, "Resonance", ionCode); + } + ionCode = -100323; + if (!db->GetParticle(ionCode)) { + db->AddParticle("K*(1410)-", "K*(1410)-", 1.414, kFALSE, 0.232, -1, "Resonance", ionCode); + } + ionCode = 100211; + if (!db->GetParticle(ionCode)) { + db->AddParticle("pi(1300)+", "pi(1300)+", 1.165, kFALSE, 0.400, +1, "Resonance", ionCode); + } + ionCode = -100211; + if (!db->GetParticle(ionCode)) { + db->AddParticle("pi(1300)-", "pi(1300)-", 1.165, kFALSE, 0.400, -1, "Resonance", ionCode); + } + ionCode = 202112; + if (!db->GetParticle(ionCode)) { + db->AddParticle("n(1440)0", "n(1440)0", 1.358, kFALSE, 0.350, 0, "Ion", ionCode); + } + ionCode = -202212; + if (!db->GetParticle(ionCode)) { + db->AddParticle("p(1440)bar-", "p(1440)bar-", 1.793, kFALSE, 0.350, -1, "Ion", ionCode); + } + ionCode = 202212; + if (!db->GetParticle(ionCode)) { + db->AddParticle("p(1440)+", "p(1440)+", 1.793, kFALSE, 0.350, 1, "Ion", ionCode); + } + // Xi-/+ (1820) ionCode = 123314; if (!db->GetParticle(ionCode)) { @@ -640,10 +691,47 @@ inline void O2DatabasePDG::addALICEParticles(TDatabasePDG* db) db->AddParticle("Anti-Theta_c_3100", "Anti-Theta_c_3100", 3.099, kFALSE, 83.e-6, 0, "Resonance", ionCode); // same width as D*+ (83 keV) } - if (!db->GetParticle(-ionCode)) { - db->AddParticle("Theta_c_3100", "Theta_c_3100", 3.099, kFALSE, - 83.e-6, 0, "Resonance", -ionCode); // same width as D*+ (83 keV) + db->AddAntiParticle("Theta_c_3100", -ionCode); + + // Charm resonances not present in PYTHIA (consistent with https://github.com/AliceO2Group/O2DPG/blob/master/MC/config/PWGHF/pythia8/generator/pythia8_charmhadronic_with_decays_DResoTrigger.cfg) + // Mesons + ionCode = 30433; + if (!db->GetParticle(ionCode)) { + db->AddParticle("D*_s1_Plus_2700", "D*_s1_Plus_2700", 2.714, false, 0.122, 3, "Resonance", ionCode); + } + db->AddAntiParticle("D*_s1_Minus_2700", -ionCode); + ionCode = 40433; + if (!db->GetParticle(ionCode)) { + db->AddParticle("D*_s1_Plus_2860", "D*_s1_Plus_2860", 2.859, false, 0.160, 3, "Resonance", ionCode); + } + db->AddAntiParticle("D*_s1_Minus_2860", -ionCode); + ionCode = 437; + if (!db->GetParticle(ionCode)) { + db->AddParticle("D*_s3_Plus_2860", "D*_s3_Plus_2860", 2.860, false, 0.053, 3, "Resonance", ionCode); + } + db->AddAntiParticle("D*_s3_Minus_2860", -ionCode); + + // Baryons + ionCode = 4325; + if (!db->GetParticle(ionCode)) { + db->AddParticle("Xi_c_Plus_3055", "Xi_c_Plus_3055", 3.0559, false, 0.0078, 3, "Resonance", ionCode); + } + db->AddAntiParticle("Xi_c_Minus_3055", -ionCode); + ionCode = 4326; + if (!db->GetParticle(ionCode)) { + db->AddParticle("Xi_c_Plus_3080", "Xi_c_Plus_3080", 3.0772, false, 0.0036, 3, "Resonance", ionCode); + } + db->AddAntiParticle("Xi_c_Minus_3080", -ionCode); + ionCode = 4315; + if (!db->GetParticle(ionCode)) { + db->AddParticle("Xi_c_0_3055", "Xi_c_0_3055", 3.0590, false, 0.0064, 0, "Resonance", ionCode); + } + db->AddAntiParticle("Anti-Xi_c_0_3055", -ionCode); + ionCode = 4316; + if (!db->GetParticle(ionCode)) { + db->AddParticle("Xi_c_0_3080", "Xi_c_0_3080", 3.0799, false, 0.0056, 0, "Resonance", ionCode); } + db->AddAntiParticle("Anti-Xi_c_0_3080", -ionCode); // d*(2380) - dibaryon resonance diff --git a/DataFormats/simulation/include/SimulationDataFormat/ProcessingEventInfo.h b/DataFormats/simulation/include/SimulationDataFormat/ProcessingEventInfo.h deleted file mode 100644 index 150a8272c7714..0000000000000 --- a/DataFormats/simulation/include/SimulationDataFormat/ProcessingEventInfo.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ProcessingEventInfo.h -/// \brief Encapsulated meta information about current event being processed by FairRoot (analysis) tasks -/// \author Sandro Wenzel - -#ifndef ALICEO2_DATA_EVENTINFO_H_ -#define ALICEO2_DATA_EVENTINFO_H_ - -namespace o2 -{ - -// A class encapsulating meta information about events being process -// and the data being sent by run classes such as FairRunAna. -// Can be send to processing tasks for usage so that they do no longer -// need to access the FairRootManager directly. -struct ProcessingEventInfo { - double eventTime; //! time of the current event - int eventNumber; //! the current entry - int sourceNumber; //! the current source number - bool numberSources; //! number of sources - // can be extended further -}; - -} // namespace o2 - -#endif diff --git a/DataFormats/simulation/include/SimulationDataFormat/TrackReference.h b/DataFormats/simulation/include/SimulationDataFormat/TrackReference.h index f3d41a17208f0..34d1c57aa9f0b 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/TrackReference.h +++ b/DataFormats/simulation/include/SimulationDataFormat/TrackReference.h @@ -171,7 +171,7 @@ class TrackReference float mTrackLength = 0; ///< track length from its origin in cm float mTof = 0; ///< time of flight in cm Int_t mUserId = 0; ///< optional Id defined by user - Int_t mDetectorId = 0; ///< Detector Id + Int_t mDetectorId = -1; ///< sensitive Detector Id (-1 if unknown or in passive material) SimTrackStatus mStatus; ///< encoding the track status friend std::ostream& operator<<(std::ostream&, const TrackReference&); diff --git a/DataFormats/simulation/src/DigitizationContext.cxx b/DataFormats/simulation/src/DigitizationContext.cxx index 499a478bc5148..79e36aa9fa48b 100644 --- a/DataFormats/simulation/src/DigitizationContext.cxx +++ b/DataFormats/simulation/src/DigitizationContext.cxx @@ -151,6 +151,19 @@ bool DigitizationContext::initSimKinematicsChains(std::vector& simkinem // add signal files simkinematicschains.back()->AddFile(o2::base::NameConf::getMCKinematicsFileName(mSimPrefixes[source].data()).c_str()); } + + // we add QED, if used in the digitization context + if (mEventRecordsWithQED.size() > 0) { + if (mSimPrefixes.size() >= QEDSOURCEID) { + LOG(fatal) << "Too many signal chains; crashes with QED source ID"; + } + + // it might be better to use an unordered_map for the simchains but this requires interface changes + simkinematicschains.resize(QEDSOURCEID + 1, nullptr); + simkinematicschains[QEDSOURCEID] = new TChain("o2sim"); + simkinematicschains[QEDSOURCEID]->AddFile(o2::base::DetectorNameConf::getMCKinematicsFileName(mQEDSimPrefix).c_str()); + } + return true; } @@ -439,18 +452,18 @@ std::vector> getTimeFrameBoundaries(std::vector(std::floor(orbit_timeframe_early_fractional)); auto bc_early = (uint32_t)((orbit_timeframe_early_fractional - orbit_timeframe_early_integral) * o2::constants::lhc::LHCMaxBunches); // this is the interaction record of the ti-th timeframe start - o2::InteractionRecord timeframe_start_record(0, orbit_timeframe_early_integral); + o2::InteractionRecord timeframe_start_record(0, orbit_timeframe_start); // this is the interaction record in some previous timeframe after which interactions could still // influence the ti-th timeframe according to orbitsEarly o2::InteractionRecord timeframe_early_record(bc_early, orbit_timeframe_early_integral); @@ -564,7 +577,7 @@ void DigitizationContext::applyMaxCollisionFilter(std::vector(tf_indices) = indices_old_to_new[lastindex]; // end; } else { - std::get<1>(tf_indices) = newrecords.size(); // end; + std::get<1>(tf_indices) = newrecords.size() - 1; // end; -1 since index inclusif } if (indices_old_to_new.find(previndex) != indices_old_to_new.end()) { std::get<2>(tf_indices) = indices_old_to_new[previndex]; // previous or "early" index @@ -578,11 +591,6 @@ void DigitizationContext::applyMaxCollisionFilter(std::vector> DigitizationContext::calcTimeframeIndices(long startOrbit, long orbitsPerTF, double orbitsEarly) const { auto timeframeindices = getTimeFrameBoundaries(mEventRecords, startOrbit, orbitsPerTF, orbitsEarly); - LOG(info) << "Fixed " << timeframeindices.size() << " timeframes "; - for (auto p : timeframeindices) { - LOG(info) << std::get<0>(p) << " " << std::get<1>(p) << " " << std::get<2>(p); - } - return timeframeindices; } @@ -622,6 +630,17 @@ struct pair_hash { }; } // namespace +int DigitizationContext::setInteractionVertices(std::vector> const& external_vertices) +{ + if (external_vertices.size() != mEventRecords.size()) { + LOG(error) << "Size mismatch with event record"; + return 1; + } + mInteractionVertices.clear(); + std::copy(external_vertices.begin(), external_vertices.end(), std::back_inserter(mInteractionVertices)); + return 0; +} + void DigitizationContext::sampleInteractionVertices(o2::dataformats::MeanVertexObject const& meanv) { // mapping of source x event --> index into mInteractionVertices @@ -680,11 +699,12 @@ DigitizationContext DigitizationContext::extractSingleTimeframe(int timeframeid, r.mSimPrefixes = mSimPrefixes; r.mMuBC = mMuBC; r.mBCFilling = mBCFilling; + r.mDigitizerInteractionRate = mDigitizerInteractionRate; try { auto tf_ranges = timeframeindices.at(timeframeid); auto startindex = std::get<0>(tf_ranges); - auto endindex = std::get<1>(tf_ranges); + auto endindex = std::get<1>(tf_ranges) + 1; auto earlyindex = std::get<2>(tf_ranges); if (earlyindex >= 0) { @@ -692,7 +712,7 @@ DigitizationContext DigitizationContext::extractSingleTimeframe(int timeframeid, } std::copy(mEventRecords.begin() + startindex, mEventRecords.begin() + endindex, std::back_inserter(r.mEventRecords)); std::copy(mEventParts.begin() + startindex, mEventParts.begin() + endindex, std::back_inserter(r.mEventParts)); - if (mInteractionVertices.size() > endindex) { + if (mInteractionVertices.size() >= endindex) { std::copy(mInteractionVertices.begin() + startindex, mInteractionVertices.begin() + endindex, std::back_inserter(r.mInteractionVertices)); } diff --git a/DataFormats/simulation/src/InteractionSampler.cxx b/DataFormats/simulation/src/InteractionSampler.cxx index 1936bf7dc06a9..f3ece5c51f90b 100644 --- a/DataFormats/simulation/src/InteractionSampler.cxx +++ b/DataFormats/simulation/src/InteractionSampler.cxx @@ -115,8 +115,8 @@ const o2::InteractionTimeRecord& InteractionSampler::generateCollisionTime() int InteractionSampler::simulateInteractingBC() { // Returns number of collisions assigned to selected BC - nextCollidingBC(mBCJumpGenerator.getNextValue()); + // once BC is decided, enforce at least one interaction int ncoll = mNCollBCGenerator.getNextValue(); @@ -130,6 +130,24 @@ int InteractionSampler::simulateInteractingBC() return ncoll; } +//_________________________________________________ +int FixedSkipBC_InteractionSampler::simulateInteractingBC() +{ + // Returns number of collisions assigned to selected BC + + nextCollidingBC(mEveryN); // we jump regular intervals + int ncoll = mMultiplicity; // well defined pileup + + // assign random time withing a bunch + for (int i = ncoll; i--;) { + mTimeInBC.push_back(mCollTimeGenerator.getNextValue()); + } + if (ncoll > 1) { // sort in DECREASING time order (we are reading vector from the end) + std::sort(mTimeInBC.begin(), mTimeInBC.end(), [](const float a, const float b) { return a > b; }); + } + return ncoll; +} + //_________________________________________________ void InteractionSampler::setBunchFilling(const std::string& bcFillingFile) { @@ -144,3 +162,101 @@ void InteractionSampler::setBunchFilling(const std::string& bcFillingFile) mBCFilling = *bc; delete bc; } + +// ________________________________________________ +bool NonUniformMuInteractionSampler::setBCIntensityScales(const std::vector& scales_from_vector) +{ + // Sets the intensity scales per bunch crossing index + // The length of this vector needs to be compatible with the bunch filling chosen + mBCIntensityScales = scales_from_vector; + + if (scales_from_vector.size() != mInteractingBCs.size()) { + LOG(error) << "Scaling factors and bunch filling scheme are not compatible. Not doing anything"; + return false; + } + + float sum = 0.; + for (auto v : mBCIntensityScales) { + sum += std::abs(v); + } + if (sum == 0) { + LOGP(warn, "total intensity is 0, assuming uniform"); + for (auto& v : mBCIntensityScales) { + v = 1.f; + } + } else { // normalize + float norm = mBCIntensityScales.size() / sum; + for (auto& v : mBCIntensityScales) { + v = std::abs(v) * norm; + } + } + return false; +} + +// ________________________________________________ + +bool NonUniformMuInteractionSampler::setBCIntensityScales(const TH1F& hist) +{ + return setBCIntensityScales(determineBCIntensityScalesFromHistogram(hist)); +} + +std::vector NonUniformMuInteractionSampler::determineBCIntensityScalesFromHistogram(const TH1F& hist) +{ + if (mInteractingBCs.size() == 0) { + LOG(error) << " Initialize bunch crossing scheme before assigning scales"; + } + std::vector scales; + // we go through the BCs and query the count from histogram + for (auto bc : mInteractingBCs) { + scales.push_back(hist.GetBinContent(bc + 1)); + } + return scales; +} + +int NonUniformMuInteractionSampler::getBCJump() const +{ + auto muFunc = [this](int bc_position) { + return mBCIntensityScales[bc_position % mInteractingBCs.size()] * mMuBC; + }; + + double U = gRandom->Rndm(); // uniform (0,1) + double T = -std::log(1.0 - U); // threshold + double sumMu = 0.0; + int offset = 0; + auto bcStart = mCurrBCIdx; // the current bc + + while (sumMu < T) { + auto mu_here = muFunc(bcStart + offset); // mu at next BC + sumMu += mu_here; + if (sumMu >= T) { + break; // found BC with at least one collision + } + ++offset; + } + return offset; +} + +int NonUniformMuInteractionSampler::simulateInteractingBC() +{ + nextCollidingBC(getBCJump()); + + auto muFunc = [this](int bc_position) { + return mBCIntensityScales[bc_position % mInteractingBCs.size()] * mMuBC; + }; + + // now sample number of collisions in chosenBC, conditioned >=1: + double mu_chosen = muFunc(mCurrBCIdx); // or does it need to be mCurrBCIdx + int ncoll = 0; + do { + ncoll = gRandom->Poisson(mu_chosen); + } while (ncoll == 0); + + // assign random time withing a bunch + for (int i = ncoll; i--;) { + mTimeInBC.push_back(mCollTimeGenerator.getNextValue()); + } + if (ncoll > 1) { // sort in DECREASING time order (we are reading vector from the end) + std::sort(mTimeInBC.begin(), mTimeInBC.end(), [](const float a, const float b) { return a > b; }); + } + return ncoll; +} \ No newline at end of file diff --git a/DataFormats/simulation/src/SimulationDataLinkDef.h b/DataFormats/simulation/src/SimulationDataLinkDef.h index 8a1e0c536c089..8f74bd757e791 100644 --- a/DataFormats/simulation/src/SimulationDataLinkDef.h +++ b/DataFormats/simulation/src/SimulationDataLinkDef.h @@ -24,6 +24,8 @@ #pragma link off all functions; #pragma link C++ class o2::steer::InteractionSampler + ; +#pragma link C++ class o2::steer::FixedSkipBC_InteractionSampler + ; +#pragma link C++ class o2::steer::NonUniformMuInteractionSampler + ; #pragma link C++ class o2::sim::StackParam + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::sim::StackParam> + ; #pragma link C++ class o2::MCTrackT < double> + ; diff --git a/DataFormats/simulation/test/testBasicHits.cxx b/DataFormats/simulation/test/testBasicHits.cxx index e81c173fedae8..ccd16ae7a3671 100644 --- a/DataFormats/simulation/test/testBasicHits.cxx +++ b/DataFormats/simulation/test/testBasicHits.cxx @@ -66,7 +66,7 @@ BOOST_AUTO_TEST_CASE(BasicXYZHit_ROOTIO) } // same for double valued hits - using HitTypeD = BasicXYZEHit; + using HitTypeD = BasicXYZEHit; HitTypeD hitD(1., 2., 3., 0.01, -1.1, -1, 1); // try writing hit to a TBuffer diff --git a/DataFormats/simulation/test/testInteractionSampler.cxx b/DataFormats/simulation/test/testInteractionSampler.cxx new file mode 100644 index 0000000000000..b1b3691884ccf --- /dev/null +++ b/DataFormats/simulation/test/testInteractionSampler.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. + +#define BOOST_TEST_MODULE Test InteractionSampler class +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include +#include "SimulationDataFormat/InteractionSampler.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/AggregatedRunInfo.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "TFile.h" +#include "TGrid.h" +#include + +namespace o2 +{ + +BOOST_AUTO_TEST_CASE(NonUniformSampler) +{ + auto run_number = 559827; + TGrid::Connect("alien"); + if (gGrid) { + auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), run_number); + + o2::steer::NonUniformMuInteractionSampler sampler; + sampler.setBunchFilling(runInfo.grpLHC->getBunchFilling()); + + // the test distribution provided by Igor Altsybeev + auto distr_file = TFile::Open("alien:///alice/cern.ch/user/s/swenzel/AliceO2_TestData/NBcVTX_559827/hBcTVX_data_PbPb_24ar_559827.root"); + + // + if (distr_file && !distr_file->IsZombie()) { + auto hist = distr_file->Get("hBcTVX"); + if (hist) { + sampler.init(); + sampler.setBCIntensityScales(*hist); + + // sample into a vector of a certain size + std::vector samples; + + int N = 100000; + samples.resize(N); + + sampler.generateCollisionTimes(samples); + + // fill an output histogram + auto output_hist = (TH1F*)hist->Clone("h2"); // make a full copy + output_hist->Reset(); + + for (const auto& sample : samples) { + output_hist->Fill(sample.bc); + } + + // Write out + auto fout = TFile::Open("NBCVTX_out.root", "RECREATE"); + fout->WriteObject(output_hist, "NBcVTX"); + fout->Close(); + + // compare mean values of original and newly sampled hist + BOOST_CHECK_CLOSE(hist->GetMean(), output_hist->GetMean(), 0.5); + } + } + } +} + +} // namespace o2 diff --git a/Detectors/AOD/CMakeLists.txt b/Detectors/AOD/CMakeLists.txt index acd703dcc6be7..827b23b3e4cdd 100644 --- a/Detectors/AOD/CMakeLists.txt +++ b/Detectors/AOD/CMakeLists.txt @@ -19,6 +19,7 @@ target_link_libraries( O2::FDDWorkflow O2::FV0Workflow O2::Framework + O2::FrameworkAnalysisSupport O2::GlobalTracking O2::GlobalTrackingWorkflow O2::ITSMFTWorkflow @@ -42,14 +43,14 @@ o2_add_executable( COMPONENT_NAME aod-producer TARGETVARNAME targetName SOURCES src/aod-producer-workflow.cxx src/AODProducerWorkflowSpec.cxx src/AODMcProducerHelpers.cxx - PUBLIC_LINK_LIBRARIES internal::AODProducerWorkflow O2::Version + PUBLIC_LINK_LIBRARIES internal::AODProducerWorkflow O2::Version nlohmann_json::nlohmann_json ) o2_add_executable( workflow COMPONENT_NAME aod-mc-producer SOURCES src/aod-mc-producer-workflow.cxx src/AODMcProducerWorkflowSpec.cxx src/AODMcProducerHelpers.cxx - PUBLIC_LINK_LIBRARIES internal::AODProducerWorkflow O2::Version + PUBLIC_LINK_LIBRARIES internal::AODProducerWorkflow O2::Version nlohmann_json::nlohmann_json ) o2_add_executable( @@ -75,7 +76,9 @@ o2_add_executable( O2::DataFormatsFT0 O2::Steer O2::ZDCBase -) + O2::FrameworkAnalysisSupport + nlohmann_json::nlohmann_json + ) if (OpenMP_CXX_FOUND) target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) diff --git a/Detectors/AOD/include/AODProducerWorkflow/AODMcProducerHelpers.h b/Detectors/AOD/include/AODProducerWorkflow/AODMcProducerHelpers.h index 42431d19cb210..5e9cd445b576b 100644 --- a/Detectors/AOD/include/AODProducerWorkflow/AODMcProducerHelpers.h +++ b/Detectors/AOD/include/AODProducerWorkflow/AODMcProducerHelpers.h @@ -315,7 +315,8 @@ uint32_t updateParticles(const ParticleCursor& cursor, bool background = false, uint32_t weightMask = 0xFFFFFFF0, uint32_t momentumMask = 0xFFFFFFF0, - uint32_t positionMask = 0xFFFFFFF0); + uint32_t positionMask = 0xFFFFFFF0, + bool signalFilter = false); } // namespace o2::aodmchelpers #endif /* O2_AODMCPRODUCER_HELPERS */ diff --git a/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h b/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h index b89acaa41066f..02f1b2582d74b 100644 --- a/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h +++ b/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h @@ -19,6 +19,10 @@ #include "DataFormatsGlobalTracking/RecoContainer.h" #include "DataFormatsPHOS/Cell.h" #include "DataFormatsTRD/TrackTRD.h" +#include "TRDBase/PadCalibrationsAliases.h" +#include "DataFormatsTRD/NoiseCalibration.h" +#include "DataFormatsTRD/CalGain.h" +#include "DataFormatsTRD/Constants.h" #include "DetectorsBase/GRPGeomHelper.h" #include "DetectorsBase/Propagator.h" #include "Framework/DataProcessorSpec.h" @@ -44,6 +48,14 @@ using DataRequest = o2::globaltracking::DataRequest; namespace o2::aodproducer { +/// helper struct to keep mapping of colIndex to MC labels and bunch crossing +struct MCColInfo { + int colIndex; + int sourceID; + int eventID; + int64_t bc; // global bunch crossing +}; + /// A structure or container to organize bunch crossing data of a timeframe /// and to facilitate fast lookup and search within bunch crossings. class BunchCrossings @@ -215,7 +227,7 @@ enum struct AODProducerStreamerFlags : uint8_t { class AODProducerWorkflowDPL : public Task { public: - AODProducerWorkflowDPL(GID::mask_t src, std::shared_ptr dataRequest, std::shared_ptr gr, bool enableSV, bool useMC = true, bool enableFITextra = false) : mUseMC(useMC), mEnableSV(enableSV), mEnableFITextra(enableFITextra), mInputSources(src), mDataRequest(dataRequest), mGGCCDBRequest(gr) {} + AODProducerWorkflowDPL(GID::mask_t src, std::shared_ptr dataRequest, std::shared_ptr gr, bool enableSV, bool useMC = true, bool enableFITextra = false, bool enableTRDextra = false) : mUseMC(useMC), mEnableSV(enableSV), mEnableFITextra(enableFITextra), mEnableTRDextra(enableTRDextra), mInputSources(src), mDataRequest(dataRequest), mGGCCDBRequest(gr) {} ~AODProducerWorkflowDPL() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -237,6 +249,9 @@ class AODProducerWorkflowDPL : public Task bool mThinTracks{false}; bool mPropTracks{false}; bool mPropMuons{false}; + bool mStoreAllMFTCov{false}; + float mTrackQCKeepGlobalTracks{false}; + float mTrackQCRetainOnlydEdx{false}; float mTrackQCFraction{0.00}; int64_t mTrackQCNTrCut{4}; float mTrackQCDCAxy{3.}; @@ -246,7 +261,11 @@ class AODProducerWorkflowDPL : public Task std::mt19937 mGenerator{}; ///< random generator for trackQA sampling o2::base::Propagator::MatCorrType mMatCorr{o2::base::Propagator::MatCorrType::USEMatCorrLUT}; o2::dataformats::MeanVertexObject mVtx; - float mMinPropR{o2::constants::geom::XTPCInnerRef + 0.1f}; + float mMaxPropXiu{5.0f}; // max X_IU for which track is to be propagated if mPropTracks is true. (other option: o2::constants::geom::XTPCInnerRef + 0.1f) + + const o2::trd::LocalGainFactor* mTRDLocalGain; // TRD local gain factors from krypton calibration + const o2::trd::CalGain* mTRDGainCalib; // TRD time-dependent gain calib at chamber level + const o2::trd::NoiseStatusMCM* mTRDNoiseMap; // TRD noise map std::unordered_set mGIDUsedBySVtx; std::unordered_set mGIDUsedByStr; @@ -256,8 +275,10 @@ class AODProducerWorkflowDPL : public Task int mNThreads = 1; bool mUseMC = true; + bool mUseSigFiltMC = false; // enable signal filtering for MC with embedding bool mEnableSV = true; // enable secondary vertices bool mEnableFITextra = false; + bool mEnableTRDextra = false; bool mFieldON = false; const float cSpeed = 0.029979246f; // speed of light in TOF units @@ -271,9 +292,12 @@ class AODProducerWorkflowDPL : public Task TString mAnchorPass{""}; TString mAnchorProd{""}; TString mRecoPass{""}; + std::string mAODParent{""}; // link to possible parent AOD file (MC embedding,...) + TString mUser{"aliprod"}; // who created this AOD (aliprod, alidaq, individual users) TStopwatch mTimer; bool mEMCselectLeading{false}; uint64_t mEMCALTrgClassMask = 0; + size_t mCurrentTRDTrigID = 0; // current index of the TRD trigger record, to speed up search // unordered map connects global indices and table indices of barrel tracks std::unordered_map mGIDToTableID; @@ -521,8 +545,11 @@ class AODProducerWorkflowDPL : public Task template void addToTracksQATable(TracksQACursorType& tracksQACursor, TrackQA& trackQAInfoHolder); - template - void addToMFTTracksTable(mftTracksCursorType& mftTracksCursor, AmbigMFTTracksCursorType& ambigMFTTracksCursor, + template + void addToTRDsExtra(const o2::globaltracking::RecoContainer& recoData, TRDsExtraCursorType& trdExtraCursor, const GIndex& trkIdx, int trkTableIdx); + + template + void addToMFTTracksTable(mftTracksCursorType& mftTracksCursor, mftTracksCovCursorType& mftTracksCovCursor, AmbigMFTTracksCursorType& ambigMFTTracksCursor, GIndex trackID, const o2::globaltracking::RecoContainer& data, int collisionID, std::uint64_t collisionBC, const std::map& bcsMap); @@ -540,7 +567,7 @@ class AODProducerWorkflowDPL : public Task // helper for track tables // * fills tables collision by collision // * interaction time is for TOF information - template void fillTrackTablesPerCollision(int collisionID, @@ -552,6 +579,7 @@ class AODProducerWorkflowDPL : public Task TracksCovCursorType& tracksCovCursor, TracksExtraCursorType& tracksExtraCursor, TracksQACursorType& tracksQACursor, + TRDsExtraCursorType& trdsExtraCursor, AmbigTracksCursorType& ambigTracksCursor, MFTTracksCursorType& mftTracksCursor, MFTTracksCovCursorType& mftTracksCovCursor, @@ -642,7 +670,7 @@ class AODProducerWorkflowDPL : public Task const gsl::span& primVer2TRefs, const gsl::span& GIndices, const o2::globaltracking::RecoContainer& data, - const std::vector>& mcColToEvSrc); + const std::vector& mcColToEvSrc); template void fillMCTrackLabelsTable(MCTrackLabelCursorType& mcTrackLabelCursor, @@ -676,7 +704,7 @@ class AODProducerWorkflowDPL : public Task }; /// create a processor spec -framework::DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, bool enableST, bool useMC, bool CTPConfigPerRun, bool enableFITextra); +framework::DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, bool enableST, bool useMC, bool CTPConfigPerRun, bool enableFITextra, bool enableTRDextra); // helper interface for calo cells to "befriend" emcal and phos cells class CellHelper diff --git a/Detectors/AOD/src/AODMcProducerHelpers.cxx b/Detectors/AOD/src/AODMcProducerHelpers.cxx index 1a01f103dcfdb..a7093e0048c25 100644 --- a/Detectors/AOD/src/AODMcProducerHelpers.cxx +++ b/Detectors/AOD/src/AODMcProducerHelpers.cxx @@ -305,7 +305,8 @@ uint32_t updateParticles(const ParticleCursor& cursor, bool background, uint32_t weightMask, uint32_t momentumMask, - uint32_t positionMask) + uint32_t positionMask, + bool signalFilter) { using o2::mcutils::MCTrackNavigator; using namespace o2::aod::mcparticle::enums; @@ -354,6 +355,9 @@ uint32_t updateParticles(const ParticleCursor& cursor, continue; } } + if (background && signalFilter) { + continue; + } // Store this particle. We mark that putting a 1 in the // `toStore` mapping. This will later on be updated with the diff --git a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx index 2b133770357fc..8365628f1644b 100644 --- a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx +++ b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx @@ -33,7 +33,6 @@ #include "DataFormatsPHOS/TriggerRecord.h" #include "DataFormatsPHOS/EventHandler.h" #include "DataFormatsTPC/TrackTPC.h" -#include "DataFormatsTRD/TriggerRecord.h" #include "DataFormatsZDC/BCRecData.h" #include "DataFormatsZDC/ZDCEnergy.h" #include "DataFormatsZDC/ZDCTDCData.h" @@ -45,6 +44,9 @@ #include "CommonDataFormat/InteractionRecord.h" #include "DataFormatsTRD/TrackTRD.h" #include "DataFormatsTRD/TrackTriggerRecord.h" +#include "DataFormatsTRD/CalibratedTracklet.h" +#include "DataFormatsTRD/TriggerRecord.h" +#include "DataFormatsTRD/Tracklet64.h" #include "DataFormatsGlobalTracking/RecoContainer.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ConfigParamRegistry.h" @@ -58,7 +60,7 @@ #include "GlobalTracking/MatchGlobalFwd.h" #include "MCHTracking/TrackExtrap.h" #include "MCHTracking/TrackParam.h" -#include "ITSMFTBase/DPLAlpideParam.h" +#include "DataFormatsITSMFT/DPLAlpideParam.h" #include "DetectorsVertexing/PVertexerParams.h" #include "ReconstructionDataFormats/GlobalFwdTrack.h" #include "ReconstructionDataFormats/GlobalTrackID.h" @@ -102,6 +104,8 @@ #ifdef WITH_OPENMP #include #endif +#include +#include using namespace o2::framework; using namespace o2::math_utils::detail; @@ -361,10 +365,10 @@ void AODProducerWorkflowDPL::addToTracksQATable(TracksQACursorType& tracksQACurs { tracksQACursor( trackQAInfoHolder.trackID, - truncateFloatFraction(trackQAInfoHolder.tpcTime0, mTPCTime0), + mTrackQCRetainOnlydEdx ? 0.0f : truncateFloatFraction(trackQAInfoHolder.tpcTime0, mTPCTime0), truncateFloatFraction(trackQAInfoHolder.tpcdEdxNorm, mTrackSignal), - trackQAInfoHolder.tpcdcaR, - trackQAInfoHolder.tpcdcaZ, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.tpcdcaR, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.tpcdcaZ, trackQAInfoHolder.tpcClusterByteMask, trackQAInfoHolder.tpcdEdxMax0R, trackQAInfoHolder.tpcdEdxMax1R, @@ -374,22 +378,137 @@ void AODProducerWorkflowDPL::addToTracksQATable(TracksQACursorType& tracksQACurs trackQAInfoHolder.tpcdEdxTot1R, trackQAInfoHolder.tpcdEdxTot2R, trackQAInfoHolder.tpcdEdxTot3R, - trackQAInfoHolder.dRefContY, - trackQAInfoHolder.dRefContZ, - trackQAInfoHolder.dRefContSnp, - trackQAInfoHolder.dRefContTgl, - trackQAInfoHolder.dRefContQ2Pt, - trackQAInfoHolder.dRefGloY, - trackQAInfoHolder.dRefGloZ, - trackQAInfoHolder.dRefGloSnp, - trackQAInfoHolder.dRefGloTgl, - trackQAInfoHolder.dRefGloQ2Pt, - trackQAInfoHolder.dTofdX, - trackQAInfoHolder.dTofdZ); + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefContY, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefContZ, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefContSnp, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefContTgl, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefContQ2Pt, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefGloY, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefGloZ, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefGloSnp, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefGloTgl, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefGloQ2Pt, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dTofdX, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dTofdZ); +} + +template +void AODProducerWorkflowDPL::addToTRDsExtra(const o2::globaltracking::RecoContainer& recoData, TRDsExtraCursorType& trdExtraCursor, const GIndex& trkIdx, int trkTableIdx) +{ + int q0s[6] = {-1}, q1s[6] = {-1}, q2s[6] = {-1}; + float q0sCor[6] = {-1}, q1sCor[6] = {-1}, q2sCor[6] = {-1}; + float ttgls[6] = {-999}, tphis[6] = {-999}; + + auto contributorsGID = recoData.getSingleDetectorRefs(trkIdx); + if (!contributorsGID[GIndex::Source::TRD].isIndexSet()) { // should be redunant + return; + } + const auto& trk = recoData.getTrack(contributorsGID[GIndex::Source::TRD]); + o2::track::TrackPar trkC{contributorsGID[GIndex::Source::ITSTPC].isIndexSet() ? recoData.getTPCITSTrack(contributorsGID[GIndex::Source::ITSTPC]).getParamOut() : recoData.getTPCTrack(contributorsGID[GIndex::Source::TPC]).getParamOut()}; + const auto& trklets = recoData.getTRDTracklets(); + const auto& ctrklets = recoData.getTRDCalibratedTracklets(); + for (int iLay{0}; iLay < 6; ++iLay) { + q0s[iLay] = q1s[iLay] = q2s[iLay] = -1; + q0sCor[iLay] = q1sCor[iLay] = q2sCor[iLay] = -1; + tphis[iLay] = ttgls[iLay] = -999; + auto trkltId = trk.getTrackletIndex(iLay); + if (trkltId < 0) { + continue; + } + const auto& tracklet = trklets[trkltId]; + if (mTRDNoiseMap->isTrackletFromNoisyMCM(tracklet)) { + continue; + } + // we need to propagate into TRD local system + int trkltDet = tracklet.getDetector(); + int trkltSec = trkltDet / 30; + if (trkltSec != o2::math_utils::angle2Sector(trkC.getAlpha())) { + if (!trkC.rotate(o2::math_utils::sector2Angle(trkltSec))) { + break; + } + } + if (!o2::base::Propagator::Instance()->PropagateToXBxByBz(trkC, ctrklets[trkltId].getX(), o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, mMatCorr)) { + break; + } + + auto tphi = trkC.getSnp() / std::sqrt((1.f - trkC.getSnp()) * (1.f + trkC.getSnp())); + auto trackletLength = std::sqrt(1.f + tphi * tphi + trkC.getTgl() * trkC.getTgl()); + float cor = mTRDLocalGain->getValue(tracklet.getHCID() / 2, tracklet.getPadCol(), tracklet.getPadRow()) * mTRDGainCalib->getMPVdEdx(tracklet.getDetector()) / o2::trd::constants::MPVDEDXDEFAULT * trackletLength; + q0s[iLay] = tracklet.getQ0(); + q1s[iLay] = tracklet.getQ1(); + q2s[iLay] = tracklet.getQ2(); + q0sCor[iLay] = (float)tracklet.getQ0() / cor; + q1sCor[iLay] = (float)tracklet.getQ1() / cor; + q2sCor[iLay] = (float)tracklet.getQ2() / cor; + ttgls[iLay] = trkC.getTgl(); + tphis[iLay] = tphi; + + // z-row merging, we want to merge only with tracklets from the same trigger record + if (trk.getIsCrossingNeighbor(iLay) && trk.getHasNeighbor()) { + // find the trigger the tracklet belongs to + auto trigsTRD = recoData.getTRDTriggerRecords(); + size_t trdSelID = -1; + + const auto& trig = trigsTRD[mCurrentTRDTrigID]; + bool foundTRDTrigger = false; + // first check current trigger + if (trkltId >= trig.getFirstTracklet() && trkltId < trig.getFirstTracklet() + trig.getNumberOfTracklets()) { + trdSelID = mCurrentTRDTrigID; + foundTRDTrigger = true; + } else { + // then check next trigger + if (mCurrentTRDTrigID < trigsTRD.size() - 1) { + const auto& trig = trigsTRD[mCurrentTRDTrigID + 1]; + if (trkltId >= trig.getFirstTracklet() && trkltId < trig.getFirstTracklet() + trig.getNumberOfTracklets()) { + trdSelID = mCurrentTRDTrigID + 1; + foundTRDTrigger = true; + } + } + } + + size_t low = 0, up = trigsTRD.size() - 1; + + // otherwise binary search + while (low <= up && !foundTRDTrigger) { + trdSelID = low + std::floor((up - low) / 2); + const auto& trig = trigsTRD[trdSelID]; + if (trig.getFirstTracklet() > trkltId) { + up = trdSelID - 1; + } else { + if (trig.getFirstTracklet() + trig.getNumberOfTracklets() <= trkltId) { + low = trdSelID + 1; + } else { + foundTRDTrigger = true; + } + } + } + //------------------- + mCurrentTRDTrigID = trdSelID; + const auto& trigSel = trigsTRD[trdSelID]; + + // loop on other tracklets from the same trigger record + for (const auto& trklt : trklets.subspan(trigSel.getFirstTracklet(), trigSel.getNumberOfTracklets())) { + if (tracklet.getTrackletWord() == trklt.getTrackletWord() || tracklet.getDetector() != trklt.getDetector()) { + continue; + } + if (std::abs(tracklet.getPadCol() - trklt.getPadCol()) <= 1 && std::abs(tracklet.getPadRow() - trklt.getPadRow()) == 1) { + cor = mTRDLocalGain->getValue(trklt.getHCID() / 2, trklt.getPadCol(), trklt.getPadRow()) * mTRDGainCalib->getMPVdEdx(tracklet.getDetector()) / o2::trd::constants::MPVDEDXDEFAULT * trackletLength; + q0s[iLay] += trklt.getQ0(); + q1s[iLay] += trklt.getQ1(); + q2s[iLay] += trklt.getQ2(); + q0sCor[iLay] += (float)trklt.getQ0() / cor; + q1sCor[iLay] += (float)trklt.getQ1() / cor; + q2sCor[iLay] += (float)trklt.getQ2() / cor; + } + } + } + } + + trdExtraCursor(trkTableIdx, q0s, q1s, q2s, q0sCor, q1sCor, q2sCor, ttgls, tphis); } -template -void AODProducerWorkflowDPL::addToMFTTracksTable(mftTracksCursorType& mftTracksCursor, AmbigMFTTracksCursorType& ambigMFTTracksCursor, +template +void AODProducerWorkflowDPL::addToMFTTracksTable(mftTracksCursorType& mftTracksCursor, mftTracksCovCursorType& mftTracksCovCursor, AmbigMFTTracksCursorType& ambigMFTTracksCursor, GIndex trackID, const o2::globaltracking::RecoContainer& data, int collisionID, std::uint64_t collisionBC, const std::map& bcsMap) { @@ -424,12 +543,35 @@ void AODProducerWorkflowDPL::addToMFTTracksTable(mftTracksCursorType& mftTracksC truncateFloatFraction(track.getTrackChi2(), mTrackChi2), truncateFloatFraction(trackTime, mTrackTime), truncateFloatFraction(trackTimeRes, mTrackTimeError)); + if (mStoreAllMFTCov) { + float sX = TMath::Sqrt(track.getSigma2X()); + float sY = TMath::Sqrt(track.getSigma2Y()); + float sPhi = TMath::Sqrt(track.getSigma2Phi()); + float sTgl = TMath::Sqrt(track.getSigma2Tanl()); + float sQ2Pt = TMath::Sqrt(track.getSigma2InvQPt()); + + mftTracksCovCursor(mTableTrMFTID, + truncateFloatFraction(sX, mTrackCovDiag), + truncateFloatFraction(sY, mTrackCovDiag), + truncateFloatFraction(sPhi, mTrackCovDiag), + truncateFloatFraction(sTgl, mTrackCovDiag), + truncateFloatFraction(sQ2Pt, mTrackCovDiag), + (Char_t)(128. * track.getCovariances()(0, 1) / (sX * sY)), + (Char_t)(128. * track.getCovariances()(0, 2) / (sPhi * sX)), + (Char_t)(128. * track.getCovariances()(1, 2) / (sPhi * sY)), + (Char_t)(128. * track.getCovariances()(0, 3) / (sTgl * sX)), + (Char_t)(128. * track.getCovariances()(1, 3) / (sTgl * sY)), + (Char_t)(128. * track.getCovariances()(2, 3) / (sTgl * sPhi)), + (Char_t)(128. * track.getCovariances()(0, 4) / (sQ2Pt * sX)), + (Char_t)(128. * track.getCovariances()(1, 4) / (sQ2Pt * sY)), + (Char_t)(128. * track.getCovariances()(2, 4) / (sQ2Pt * sPhi)), + (Char_t)(128. * track.getCovariances()(3, 4) / (sQ2Pt * sTgl))); + } if (needBCSlice) { ambigMFTTracksCursor(mTableTrMFTID, bcSlice); } } - -template void AODProducerWorkflowDPL::fillTrackTablesPerCollision(int collisionID, @@ -441,6 +583,7 @@ void AODProducerWorkflowDPL::fillTrackTablesPerCollision(int collisionID, TracksCovCursorType& tracksCovCursor, TracksExtraCursorType& tracksExtraCursor, TracksQACursorType& tracksQACursor, + TRDsExtraCursor& trdsExtraCursor, AmbigTracksCursorType& ambigTracksCursor, MFTTracksCursorType& mftTracksCursor, MFTTracksCovCursorType& mftTracksCovCursor, @@ -460,10 +603,13 @@ void AODProducerWorkflowDPL::fillTrackTablesPerCollision(int collisionID, int nToReserve = end - start; // + last index for a given table if (src == GIndex::Source::MFT) { mftTracksCursor.reserve(nToReserve + mftTracksCursor.lastIndex()); + if (mStoreAllMFTCov) { + mftTracksCovCursor.reserve(nToReserve + mftTracksCovCursor.lastIndex()); + } } else if (src == GIndex::Source::MCH || src == GIndex::Source::MFTMCH || src == GIndex::Source::MCHMID) { fwdTracksCursor.reserve(nToReserve + fwdTracksCursor.lastIndex()); fwdTracksCovCursor.reserve(nToReserve + fwdTracksCovCursor.lastIndex()); - if (src == GIndex::Source::MFTMCH) { + if (!mStoreAllMFTCov && src == GIndex::Source::MFTMCH) { mftTracksCovCursor.reserve(nToReserve + mftTracksCovCursor.lastIndex()); } } else { @@ -478,7 +624,7 @@ void AODProducerWorkflowDPL::fillTrackTablesPerCollision(int collisionID, if (trackIndex.isAmbiguous() && mGIDToTableMFTID.find(trackIndex) != mGIDToTableMFTID.end()) { // was it already stored ? continue; } - addToMFTTracksTable(mftTracksCursor, ambigMFTTracksCursor, trackIndex, data, collisionID, collisionBC, bcsMap); + addToMFTTracksTable(mftTracksCursor, mftTracksCovCursor, ambigMFTTracksCursor, trackIndex, data, collisionID, collisionBC, bcsMap); mGIDToTableMFTID.emplace(trackIndex, mTableTrMFTID); mTableTrMFTID++; } else if (src == GIndex::Source::MCH || src == GIndex::Source::MFTMCH || src == GIndex::Source::MCHMID) { // FwdTracks tracks are treated separately since they are stored in a different table @@ -497,7 +643,7 @@ void AODProducerWorkflowDPL::fillTrackTablesPerCollision(int collisionID, float weight = 0; static std::uniform_real_distribution<> distr(0., 1.); - bool writeQAData = o2::math_utils::Tsallis::downsampleTsallisCharged(data.getTrackParam(trackIndex).getPt(), mTrackQCFraction, mSqrtS, weight, distr(mGenerator)); + bool writeQAData = o2::math_utils::Tsallis::downsampleTsallisCharged(data.getTrackParam(trackIndex).getPt(), mTrackQCFraction, mSqrtS, weight, distr(mGenerator)) || ((src != GIndex::TPC || mGIDUsedBySVtx.find(trackIndex) != mGIDUsedBySVtx.end() || mGIDUsedByStr.find(trackIndex) != mGIDUsedByStr.end()) && mTrackQCKeepGlobalTracks); auto extraInfoHolder = processBarrelTrack(collisionID, collisionBC, trackIndex, data, bcsMap); if (writeQAData) { @@ -538,7 +684,7 @@ void AODProducerWorkflowDPL::fillTrackTablesPerCollision(int collisionID, } const auto& trOrig = data.getTrackParam(trackIndex); bool isProp = false; - if (mPropTracks && trOrig.getX() < mMinPropR && + if (mPropTracks && trOrig.getX() < mMaxPropXiu && mGIDUsedBySVtx.find(trackIndex) == mGIDUsedBySVtx.end() && mGIDUsedByStr.find(trackIndex) == mGIDUsedByStr.end()) { // Do not propagate track assoc. to V0s and str. tracking auto trackPar(trOrig); @@ -551,7 +697,9 @@ void AODProducerWorkflowDPL::fillTrackTablesPerCollision(int collisionID, addToTracksTable(tracksCursor, tracksCovCursor, trOrig, collisionID, aod::track::TrackIU); } addToTracksExtraTable(tracksExtraCursor, extraInfoHolder); - + if (mEnableTRDextra && trackIndex.includesDet(GIndex::Source::TRD)) { + addToTRDsExtra(data, trdsExtraCursor, trackIndex, mTableTrID); + } // collecting table indices of barrel tracks for V0s table if (extraInfoHolder.bcSlice[0] >= 0 && collisionID < 0) { ambigTracksCursor(mTableTrID, extraInfoHolder.bcSlice); @@ -808,22 +956,24 @@ void AODProducerWorkflowDPL::addToFwdTracksTable(FwdTracksCursorType& fwdTracksC float sX = TMath::Sqrt(mfttrack.getSigma2X()), sY = TMath::Sqrt(mfttrack.getSigma2Y()), sPhi = TMath::Sqrt(mfttrack.getSigma2Phi()), sTgl = TMath::Sqrt(mfttrack.getSigma2Tanl()), sQ2Pt = TMath::Sqrt(mfttrack.getSigma2InvQPt()); - mftTracksCovCursor(fwdInfo.matchmfttrackid, - truncateFloatFraction(sX, mTrackCovDiag), - truncateFloatFraction(sY, mTrackCovDiag), - truncateFloatFraction(sPhi, mTrackCovDiag), - truncateFloatFraction(sTgl, mTrackCovDiag), - truncateFloatFraction(sQ2Pt, mTrackCovDiag), - (Char_t)(128. * mfttrack.getCovariances()(0, 1) / (sX * sY)), - (Char_t)(128. * mfttrack.getCovariances()(0, 2) / (sPhi * sX)), - (Char_t)(128. * mfttrack.getCovariances()(1, 2) / (sPhi * sY)), - (Char_t)(128. * mfttrack.getCovariances()(0, 3) / (sTgl * sX)), - (Char_t)(128. * mfttrack.getCovariances()(1, 3) / (sTgl * sY)), - (Char_t)(128. * mfttrack.getCovariances()(2, 3) / (sTgl * sPhi)), - (Char_t)(128. * mfttrack.getCovariances()(0, 4) / (sQ2Pt * sX)), - (Char_t)(128. * mfttrack.getCovariances()(1, 4) / (sQ2Pt * sY)), - (Char_t)(128. * mfttrack.getCovariances()(2, 4) / (sQ2Pt * sPhi)), - (Char_t)(128. * mfttrack.getCovariances()(3, 4) / (sQ2Pt * sTgl))); + if (!mStoreAllMFTCov) { + mftTracksCovCursor(fwdInfo.matchmfttrackid, + truncateFloatFraction(sX, mTrackCovDiag), + truncateFloatFraction(sY, mTrackCovDiag), + truncateFloatFraction(sPhi, mTrackCovDiag), + truncateFloatFraction(sTgl, mTrackCovDiag), + truncateFloatFraction(sQ2Pt, mTrackCovDiag), + (Char_t)(128. * mfttrack.getCovariances()(0, 1) / (sX * sY)), + (Char_t)(128. * mfttrack.getCovariances()(0, 2) / (sPhi * sX)), + (Char_t)(128. * mfttrack.getCovariances()(1, 2) / (sPhi * sY)), + (Char_t)(128. * mfttrack.getCovariances()(0, 3) / (sTgl * sX)), + (Char_t)(128. * mfttrack.getCovariances()(1, 3) / (sTgl * sY)), + (Char_t)(128. * mfttrack.getCovariances()(2, 3) / (sTgl * sPhi)), + (Char_t)(128. * mfttrack.getCovariances()(0, 4) / (sQ2Pt * sX)), + (Char_t)(128. * mfttrack.getCovariances()(1, 4) / (sQ2Pt * sY)), + (Char_t)(128. * mfttrack.getCovariances()(2, 4) / (sQ2Pt * sPhi)), + (Char_t)(128. * mfttrack.getCovariances()(3, 4) / (sQ2Pt * sTgl))); + } } std::uint64_t bcOfTimeRef; @@ -945,13 +1095,17 @@ void clearMCKeepStore(std::vector>>& st } // helper function to add a particle/track to the MC keep store -void keepMCParticle(std::vector>>& store, int source, int event, int track, int value = 1) +void keepMCParticle(std::vector>>& store, int source, int event, int track, int value = 1, bool useSigFilt = false) { if (track < 0) { LOG(warn) << "trackID is smaller than 0. Neglecting"; return; } - store[source][event][track] = value; + if (useSigFilt && source == 0) { + store[source][event][track] = -1; + } else { + store[source][event][track] = value; + } } void AODProducerWorkflowDPL::fillMCParticlesTable(o2::steer::MCKinematicsReader& mcReader, @@ -959,13 +1113,13 @@ void AODProducerWorkflowDPL::fillMCParticlesTable(o2::steer::MCKinematicsReader& const gsl::span& primVer2TRefs, const gsl::span& GIndices, const o2::globaltracking::RecoContainer& data, - const std::vector>& mcColToEvSrc) + const std::vector& mcColToEvSrc) { int NSources = 0; int NEvents = 0; for (auto& p : mcColToEvSrc) { - NSources = std::max(p[1], NSources); - NEvents = std::max(p[2], NEvents); + NSources = std::max(p.sourceID, NSources); + NEvents = std::max(p.eventID, NEvents); } NSources++; // 0 - indexed NEvents++; @@ -980,7 +1134,7 @@ void AODProducerWorkflowDPL::fillMCParticlesTable(o2::steer::MCKinematicsReader& if (!mcLabel.isValid()) { return; } - keepMCParticle(mToStore, mcLabel.getSourceID(), mcLabel.getEventID(), mcLabel.getTrackID()); + keepMCParticle(mToStore, mcLabel.getSourceID(), mcLabel.getEventID(), mcLabel.getTrackID(), 1, mUseSigFiltMC); }; // mark reconstructed MC particles to store them into the table @@ -995,7 +1149,7 @@ void AODProducerWorkflowDPL::fillMCParticlesTable(o2::steer::MCKinematicsReader& if (!mcTruth.isValid()) { continue; } - keepMCParticle(mToStore, mcTruth.getSourceID(), mcTruth.getEventID(), mcTruth.getTrackID()); + keepMCParticle(mToStore, mcTruth.getSourceID(), mcTruth.getEventID(), mcTruth.getTrackID(), 1, mUseSigFiltMC); // treating contributors of global tracks auto contributorsGID = data.getSingleDetectorRefs(trackIndex); if (contributorsGID[GIndex::Source::TPC].isIndexSet()) { @@ -1010,7 +1164,7 @@ void AODProducerWorkflowDPL::fillMCParticlesTable(o2::steer::MCKinematicsReader& if (!mcLabel.isValid()) { continue; } - keepMCParticle(mToStore, mcLabel.getSourceID(), mcLabel.getEventID(), mcLabel.getTrackID()); + keepMCParticle(mToStore, mcLabel.getSourceID(), mcLabel.getEventID(), mcLabel.getTrackID(), 1, mUseSigFiltMC); } } } @@ -1024,7 +1178,7 @@ void AODProducerWorkflowDPL::fillMCParticlesTable(o2::steer::MCKinematicsReader& if (!mcTruth.isValid()) { continue; } - keepMCParticle(mToStore, mcTruth.getSourceID(), mcTruth.getEventID(), mcTruth.getTrackID()); + keepMCParticle(mToStore, mcTruth.getSourceID(), mcTruth.getEventID(), mcTruth.getTrackID(), 1, mUseSigFiltMC); } } if (mInputSources[GIndex::PHS]) { @@ -1033,7 +1187,7 @@ void AODProducerWorkflowDPL::fillMCParticlesTable(o2::steer::MCKinematicsReader& if (!mcTruth.isValid()) { continue; } - keepMCParticle(mToStore, mcTruth.getSourceID(), mcTruth.getEventID(), mcTruth.getTrackID()); + keepMCParticle(mToStore, mcTruth.getSourceID(), mcTruth.getEventID(), mcTruth.getTrackID(), 1, mUseSigFiltMC); } } using namespace aodmchelpers; @@ -1041,9 +1195,9 @@ void AODProducerWorkflowDPL::fillMCParticlesTable(o2::steer::MCKinematicsReader& size_t offset = 0; for (auto& colInfo : mcColToEvSrc) { // loop over " <-> combined MC col. ID" key pairs - int event = colInfo[2]; - int source = colInfo[1]; - int mcColId = colInfo[0]; + int event = colInfo.eventID; + int source = colInfo.sourceID; + int mcColId = colInfo.colIndex; std::vector const& mcParticles = mcReader.getTracks(source, event); LOG(debug) << "Event=" << event << " source=" << source << " collision=" << mcColId; auto& preselect = mToStore[source][event]; @@ -1057,7 +1211,8 @@ void AODProducerWorkflowDPL::fillMCParticlesTable(o2::steer::MCKinematicsReader& source == 0, // background mMcParticleW, mMcParticleMom, - mMcParticlePos); + mMcParticlePos, + mUseSigFiltMC); mcReader.releaseTracksForSourceAndEvent(source, event); } @@ -1124,7 +1279,7 @@ void AODProducerWorkflowDPL::fillMCTrackLabelsTable(MCTrackLabelCursorType& mcTr if (!needToStore(mGIDToTableID)) { continue; } - if (mcTruth.isValid()) { // if not set, -1 will be stored + if (mcTruth.isValid()) { // if not set, -1 will be stored labelHolder.labelID = (mToStore[mcTruth.getSourceID()][mcTruth.getEventID()])[mcTruth.getTrackID()]; // defined by TPC if it contributes, otherwise: by ITS if (mcTruth.isFake()) { labelHolder.labelMask |= (0x1 << 15); @@ -1137,6 +1292,21 @@ void AODProducerWorkflowDPL::fillMCTrackLabelsTable(MCTrackLabelCursorType& mcTr } } } + if (trackIndex.includesDet(DetID::ITS)) { + auto itsGID = data.getITSContributorGID(trackIndex); + auto itsSource = itsGID.getSource(); + if (itsSource == GIndex::ITS) { + auto& itsTrack = data.getITSTrack(itsGID); + for (unsigned int iL = 0; iL < 7; ++iL) { + if (itsTrack.isFakeOnLayer(iL)) { + labelHolder.labelMask |= (0x1 << iL); + } + } + } else if (itsSource == GIndex::ITSAB) { + labelHolder.labelMask |= (data.getTrackMCLabel(itsGID).isFake() << 12); + } + } + } else if (mcTruth.isNoise()) { labelHolder.labelMask |= (0x1 << 14); } @@ -1672,10 +1842,12 @@ void AODProducerWorkflowDPL::init(InitContext& ic) { mTimer.Stop(); o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); - mLPMProdTag = ic.options().get("lpmp-prod-tag"); - mAnchorPass = ic.options().get("anchor-pass"); - mAnchorProd = ic.options().get("anchor-prod"); - mRecoPass = ic.options().get("reco-pass"); + mLPMProdTag = ic.options().get("lpmp-prod-tag"); + mAnchorPass = ic.options().get("anchor-pass"); + mAnchorProd = ic.options().get("anchor-prod"); + mUser = ic.options().get("created-by"); + mRecoPass = ic.options().get("reco-pass"); + mAODParent = ic.options().get("aod-parent"); mTFNumber = ic.options().get("aod-timeframe-id"); mRecoOnly = ic.options().get("reco-mctracks-only"); mTruncate = ic.options().get("enable-truncation"); @@ -1685,7 +1857,9 @@ void AODProducerWorkflowDPL::init(InitContext& ic) mEMCselectLeading = ic.options().get("emc-select-leading"); mThinTracks = ic.options().get("thin-tracks"); mPropTracks = ic.options().get("propagate-tracks"); + mMaxPropXiu = ic.options().get("propagate-tracks-max-xiu"); mPropMuons = ic.options().get("propagate-muons"); + mStoreAllMFTCov = ic.options().get("store-all-mft-cov"); if (auto s = ic.options().get("with-streamers"); !s.empty()) { mStreamerFlags.set(s); if (mStreamerFlags) { @@ -1695,6 +1869,8 @@ void AODProducerWorkflowDPL::init(InitContext& ic) LOGP(warn, "Specified non-default empty streamer mask!"); } } + mTrackQCKeepGlobalTracks = ic.options().get("trackqc-keepglobaltracks"); + mTrackQCRetainOnlydEdx = ic.options().get("trackqc-retainonlydedx"); mTrackQCFraction = ic.options().get("trackqc-fraction"); mTrackQCNTrCut = ic.options().get("trackqc-NTrCut"); mTrackQCDCAxy = ic.options().get("trackqc-tpc-dca"); @@ -1724,6 +1900,8 @@ void AODProducerWorkflowDPL::init(InitContext& ic) LOG(info) << "The Run number will be obtained from DPL headers"; } + mUseSigFiltMC = ic.options().get("mc-signal-filt"); + // set no truncation if selected by user if (mTruncate != 1) { LOG(info) << "Truncation is not used!"; @@ -1792,6 +1970,38 @@ void AODProducerWorkflowDPL::init(InitContext& ic) } } +namespace +{ +void add_additional_meta_info(std::vector& keys, std::vector& values) +{ + // see if we should put additional meta info (e.g. from MC) + auto aod_external_meta_info_file = getenv("AOD_ADDITIONAL_METADATA_FILE"); + if (aod_external_meta_info_file != nullptr) { + LOG(info) << "Trying to inject additional AOD meta-data from " << aod_external_meta_info_file; + if (std::filesystem::exists(aod_external_meta_info_file)) { + std::ifstream input_file(aod_external_meta_info_file); + if (input_file) { + nlohmann::json json_data; + try { + input_file >> json_data; + } catch (nlohmann::json::parse_error& e) { + std::cerr << "JSON Parse Error: " << e.what() << "\n"; + std::cerr << "Exception ID: " << e.id << "\n"; + std::cerr << "Byte position: " << e.byte << "\n"; + return; + } + // If parsing succeeds, iterate over key-value pairs + for (const auto& [key, value] : json_data.items()) { + LOG(info) << "Adding AOD MetaData" << key << " : " << value; + keys.push_back(key.c_str()); + values.push_back(value.get()); + } + } + } + } +} +} // namespace + void AODProducerWorkflowDPL::run(ProcessingContext& pc) { mTimer.Start(false); @@ -1874,6 +2084,12 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) auto cpvClustersCursor = createTableCursor(pc); auto originCursor = createTableCursor(pc); + /// Extra tables + o2::framework::Produces trdExtraCursor; + if (mEnableTRDextra) { + trdExtraCursor = createTableCursor(pc); + } + // Declare MC cursors type without adding the output for a table o2::framework::Produces mcColLabelsCursor; o2::framework::Produces mcCollisionsCursor; @@ -1993,10 +2209,8 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) zdcChannelsT); } - // keep track event/source id for each mc-collision - // using map and not unordered_map to ensure - // correct ordering when iterating over container elements - std::vector> mcColToEvSrc; + // keep track of event_id + source_id + bc for each mc-collision + std::vector mcColToEvSrc; if (mUseMC) { using namespace o2::aodmchelpers; @@ -2006,6 +2220,28 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) const auto& mcRecords = mcReader->getDigitizationContext()->getEventRecords(); const auto& mcParts = mcReader->getDigitizationContext()->getEventParts(); + // if signal filtering enabled, let's check if there are more than one source; otherwise fatalise + if (mUseSigFiltMC) { + std::vector sourceIDs{}; + for (int iCol = 0; iCol < nMCCollisions; iCol++) { + for (auto const& colPart : mcParts[iCol]) { + int sourceID = colPart.sourceID; + if (std::find(sourceIDs.begin(), sourceIDs.end(), sourceID) == sourceIDs.end()) { + sourceIDs.push_back(sourceID); + } + if (sourceIDs.size() > 1) { // we found more than one, exit + break; + } + } + if (sourceIDs.size() > 1) { // we found more than one, exit + break; + } + } + if (sourceIDs.size() <= 1) { + LOGP(fatal, "Signal filtering cannot be enabled without embedding. Please fix the configuration either enabling the embedding, or turning off the signal filtering."); + } + } + // count all parts int totalNParts = 0; for (int iCol = 0; iCol < nMCCollisions; iCol++) { @@ -2047,13 +2283,13 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) 0, sourceID); } - mcColToEvSrc.emplace_back(std::vector{iCol, sourceID, eventID}); // point background and injected signal events to one collision + mcColToEvSrc.emplace_back(MCColInfo{iCol, sourceID, eventID, globalBC}); // point background and injected signal events to one collision } } } std::sort(mcColToEvSrc.begin(), mcColToEvSrc.end(), - [](const std::vector& left, const std::vector& right) { return (left[0] < right[0]); }); + [](const MCColInfo& left, const MCColInfo& right) { return (left.colIndex < right.colIndex); }); // vector of FDD amplitudes int16_t aFDDAmplitudesA[8] = {0u}, aFDDAmplitudesC[8] = {0u}; @@ -2152,16 +2388,46 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) } if (mUseMC) { - // filling MC collision labels + // Fill MC collision labels using information from the primary vertexer. mcColLabelsCursor.reserve(primVerLabels.size()); - for (auto& label : primVerLabels) { - auto it = std::find_if(mcColToEvSrc.begin(), mcColToEvSrc.end(), - [&label](const auto& mcColInfo) { return mcColInfo[1] == label.getSourceID() && mcColInfo[2] == label.getEventID(); }); + for (size_t ivert = 0; ivert < primVerLabels.size(); ++ivert) { + const auto& label = primVerLabels[ivert]; + + // Collect all MC collision candidates matching this (sourceID, eventID) label. + // In the non-embedding case there is exactly one candidate. In the embedding + // case the same (sourceID, eventID) pair can appear in multiple collisions, + // so we need to disambiguate. + std::vector> candidates; // (colIndex, bc) + for (const auto& colInfo : mcColToEvSrc) { + if (colInfo.sourceID == label.getSourceID() && + colInfo.eventID == label.getEventID()) { + candidates.emplace_back(colInfo.colIndex, colInfo.bc); + } + } + int32_t mcCollisionID = -1; - if (it != mcColToEvSrc.end()) { - mcCollisionID = it->at(0); + if (candidates.size() == 1) { + mcCollisionID = candidates[0].first; + } else if (candidates.size() > 1) { + // Disambiguate by BC: pick the MCCollision whose BC is closest + // to the reconstructed collision's BC. + // TODO: Consider a complementary strategy using the MC labels of tracks + // associated to the primary vertex, and/or by allowing the primary + // vertexer to return multiple MC collision labels per vertex. + const auto& timeStamp = primVertices[ivert].getTimeStamp(); + const double interactionTime = timeStamp.getTimeStamp() * 1E3; // us -> ns + const auto recoBC = relativeTime_to_GlobalBC(interactionTime); + int64_t bestDiff = std::numeric_limits::max(); + for (const auto& [colIndex, bc] : candidates) { + const auto bcDiff = std::abs(static_cast(bc) - static_cast(recoBC)); + if (bcDiff < bestDiff) { + bestDiff = bcDiff; + mcCollisionID = colIndex; + } + } } - uint16_t mcMask = 0; // todo: set mask using normalized weights? + + uint16_t mcMask = 0; // TODO: set mask using normalised weights mcColLabelsCursor(mcCollisionID, mcMask); } } @@ -2212,14 +2478,16 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) } } + mCurrentTRDTrigID = 0; // reinitialize index for TRD trigger record search // 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, std::uint64_t(-1), trackRef, primVerGIs, recoData, tracksCursor, tracksCovCursor, tracksExtraCursor, tracksQACursor, + fillTrackTablesPerCollision(-1, std::uint64_t(-1), trackRef, primVerGIs, recoData, tracksCursor, tracksCovCursor, tracksExtraCursor, tracksQACursor, trdExtraCursor, ambigTracksCursor, mftTracksCursor, mftTracksCovCursor, ambigMFTTracksCursor, fwdTracksCursor, fwdTracksCovCursor, ambigFwdTracksCursor, fwdTrkClsCursor, bcsMap); + mCurrentTRDTrigID = 0; // reinitialize index for TRD trigger record search // filling collisions and tracks into tables collisionID = 0; collisionsCursor.reserve(primVertices.size()); @@ -2258,7 +2526,7 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) auto& trackRef = primVer2TRefs[collisionID]; // passing interaction time in [ps] - fillTrackTablesPerCollision(collisionID, globalBC, trackRef, primVerGIs, recoData, tracksCursor, tracksCovCursor, tracksExtraCursor, tracksQACursor, ambigTracksCursor, + fillTrackTablesPerCollision(collisionID, globalBC, trackRef, primVerGIs, recoData, tracksCursor, tracksCovCursor, tracksExtraCursor, tracksQACursor, trdExtraCursor, ambigTracksCursor, mftTracksCursor, mftTracksCovCursor, ambigMFTTracksCursor, fwdTracksCursor, fwdTracksCovCursor, ambigFwdTracksCursor, fwdTrkClsCursor, bcsMap); collisionID++; @@ -2398,13 +2666,15 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) TString dataType = mUseMC ? "MC" : "RAW"; TString O2Version = o2::fullVersion(); TString ROOTVersion = ROOT_RELEASE; - mMetaDataKeys = {"DataType", "Run", "O2Version", "ROOTVersion", "RecoPassName", "AnchorProduction", "AnchorPassName", "LPMProductionTag"}; - mMetaDataVals = {dataType, "3", O2Version, ROOTVersion, mRecoPass, mAnchorProd, mAnchorPass, mLPMProdTag}; + mMetaDataKeys = {"DataType", "Run", "O2Version", "ROOTVersion", "RecoPassName", "AnchorProduction", "AnchorPassName", "LPMProductionTag", "CreatedBy"}; + mMetaDataVals = {dataType, "3", O2Version, ROOTVersion, mRecoPass, mAnchorProd, mAnchorPass, mLPMProdTag, mUser}; + add_additional_meta_info(mMetaDataKeys, mMetaDataVals); + pc.outputs().snapshot(Output{"AMD", "AODMetadataKeys", 0}, mMetaDataKeys); pc.outputs().snapshot(Output{"AMD", "AODMetadataVals", 0}, mMetaDataVals); pc.outputs().snapshot(Output{"TFN", "TFNumber", 0}, tfNumber); - pc.outputs().snapshot(Output{"TFF", "TFFilename", 0}, ""); + pc.outputs().snapshot(Output{"TFF", "TFFilename", 0}, mAODParent); mTimer.Stop(); } @@ -2563,6 +2833,12 @@ AODProducerWorkflowDPL::TrackExtraInfo AODProducerWorkflowDPL::processBarrelTrac if (tpcOrig.getdEdx().dEdxTotTPC == 0) { extraInfoHolder.flags |= o2::aod::track::TPCdEdxAlt; } + if (tpcOrig.hasASideClusters()) { + extraInfoHolder.flags |= o2::aod::track::TPCSideA; + } + if (tpcOrig.hasCSideClusters()) { + extraInfoHolder.flags |= o2::aod::track::TPCSideC; + } extraInfoHolder.tpcInnerParam = tpcOrig.getP() / tpcOrig.getAbsCharge(); extraInfoHolder.tpcChi2NCl = tpcOrig.getNClusters() ? tpcOrig.getChi2() / tpcOrig.getNClusters() : 0; extraInfoHolder.tpcSignal = dEdx.dEdxTotTPC; @@ -2615,7 +2891,7 @@ AODProducerWorkflowDPL::TrackQA AODProducerWorkflowDPL::processBarrelTrackQA(int o2::track::TrackParametrization tpcTMP = tpcOrig; /// get backup of the track const o2::base::Propagator::MatCorrType mMatType = o2::base::Propagator::MatCorrType::USEMatCorrLUT; /// should be parameterized const o2::dataformats::VertexBase v = mVtx.getMeanVertex(collisionID < 0 ? 0.f : data.getPrimaryVertex(collisionID).getZ()); - o2::gpu::gpustd::array dcaInfo{-999., -999.}; + std::array dcaInfo{-999., -999.}; if (prop->propagateToDCABxByBz({v.getX(), v.getY(), v.getZ()}, tpcTMP, 2.f, mMatType, &dcaInfo)) { trackQAHolder.tpcdcaR = 100. * dcaInfo[0] / sqrt(1. + trackPar.getQ2Pt() * trackPar.getQ2Pt()); trackQAHolder.tpcdcaZ = 100. * dcaInfo[1] / sqrt(1. + trackPar.getQ2Pt() * trackPar.getQ2Pt()); @@ -2680,7 +2956,7 @@ AODProducerWorkflowDPL::TrackQA AODProducerWorkflowDPL::processBarrelTrackQA(int if (auto itsContGID = data.getITSContributorGID(trackIndex); itsContGID.isIndexSet() && itsContGID.getSource() != GIndex::ITSAB) { const auto& itsOrig = data.getITSTrack(itsContGID); o2::track::TrackPar gloCopy = trackPar; - o2::track::TrackPar itsCopy = itsOrig; + o2::track::TrackPar itsCopy = itsOrig.getParamOut(); o2::track::TrackPar tpcCopy = tpcOrig; if (prop->propagateToX(gloCopy, o2::aod::track::trackQARefRadius, prop->getNominalBz(), o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, mMatCorr) && prop->propagateToAlphaX(tpcCopy, gloCopy.getAlpha(), o2::aod::track::trackQARefRadius, false, o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, 1, mMatCorr) && @@ -2921,6 +3197,11 @@ void AODProducerWorkflowDPL::updateTimeDependentParams(ProcessingContext& pc) mFieldON = std::abs(o2::base::Propagator::Instance()->getNominalBz()) > 0.01; pc.inputs().get("ctpconfig"); + if (mEnableTRDextra) { + mTRDLocalGain = pc.inputs().get("trdlocalgainfactors").get(); + mTRDNoiseMap = pc.inputs().get("trdnoisemap").get(); + mTRDGainCalib = pc.inputs().get("trdgaincalib").get(); // time dependent gain + } } if (mPropTracks) { pc.inputs().get("meanvtx"); @@ -3132,7 +3413,7 @@ void AODProducerWorkflowDPL::endOfStream(EndOfStreamContext& /*ec*/) mStreamer.reset(); } -DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, bool enableStrangenessTracking, bool useMC, bool CTPConfigPerRun, bool enableFITextra) +DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, bool enableStrangenessTracking, bool useMC, bool CTPConfigPerRun, bool enableFITextra, bool enableTRDextra) { auto dataRequest = std::make_shared(); dataRequest->inputs.emplace_back("ctpconfig", "CTP", "CTPCONFIG", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/Config", CTPConfigPerRun)); @@ -3223,6 +3504,13 @@ DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, boo OutputSpec{"TFF", "TFFilename"}, OutputSpec{"AMD", "AODMetadataKeys"}, OutputSpec{"AMD", "AODMetadataVals"}}; + /// Extra tables + if (enableTRDextra) { + outputs.push_back(OutputForTable::spec()); + dataRequest->inputs.emplace_back("trdlocalgainfactors", "TRD", "LOCALGAINFACTORS", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/LocalGainFactor")); + dataRequest->inputs.emplace_back("trdnoisemap", "TRD", "NOISEMAP", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/NoiseMapMCM")); + dataRequest->inputs.emplace_back("trdgaincalib", "TRD", "CALGAIN", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/CalGain")); + } if (useMC) { outputs.insert(outputs.end(), @@ -3246,7 +3534,7 @@ DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, boo "aod-producer-workflow", dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask(src, dataRequest, ggRequest, enableSV, useMC, enableFITextra)}, + AlgorithmSpec{adaptFromTask(src, dataRequest, ggRequest, enableSV, useMC, enableFITextra, enableTRDextra)}, Options{ ConfigParamSpec{"run-number", VariantType::Int64, -1L, {"The run-number. If left default we try to get it from DPL header."}}, ConfigParamSpec{"aod-timeframe-id", VariantType::Int64, -1L, {"Set timeframe number"}}, @@ -3256,14 +3544,20 @@ DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, boo ConfigParamSpec{"anchor-pass", VariantType::String, "", {"AnchorPassName"}}, ConfigParamSpec{"anchor-prod", VariantType::String, "", {"AnchorProduction"}}, ConfigParamSpec{"reco-pass", VariantType::String, "", {"RecoPassName"}}, + ConfigParamSpec{"aod-parent", VariantType::String, "", {"Parent AOD file name (if any)"}}, + ConfigParamSpec{"created-by", VariantType::String, "", {"Who created this AO2D"}}, ConfigParamSpec{"nthreads", VariantType::Int, std::max(1, int(std::thread::hardware_concurrency() / 2)), {"Number of threads"}}, ConfigParamSpec{"reco-mctracks-only", VariantType::Int, 0, {"Store only reconstructed MC tracks and their mothers/daughters. 0 -- off, != 0 -- on"}}, ConfigParamSpec{"ctpreadout-create", VariantType::Int, 0, {"Create CTP digits from detector readout and CTP inputs. !=1 -- off, 1 -- on"}}, ConfigParamSpec{"emc-select-leading", VariantType::Bool, false, {"Flag to select if only the leading contributing particle for an EMCal cell should be stored"}}, ConfigParamSpec{"propagate-tracks", VariantType::Bool, false, {"Propagate tracks (not used for secondary vertices) to IP"}}, + ConfigParamSpec{"propagate-tracks-max-xiu", VariantType::Float, 5.0f, {"Propagate tracks to IP if X_IU smaller than this value (and if propagate tracks enabled)"}}, ConfigParamSpec{"hepmc-update", VariantType::String, "always", {"When to update HepMC Aux tables: always - force update, never - never update, all - if all keys are present, any - when any key is present (not valid yet)"}}, ConfigParamSpec{"propagate-muons", VariantType::Bool, false, {"Propagate muons to IP"}}, + ConfigParamSpec{"store-all-mft-cov", VariantType::Bool, false, {"Store covariance matrices for all MFT tracks"}}, ConfigParamSpec{"thin-tracks", VariantType::Bool, false, {"Produce thinned track tables"}}, + ConfigParamSpec{"trackqc-keepglobaltracks", VariantType::Bool, false, {"Always keep TrackQA for global tracks"}}, + ConfigParamSpec{"trackqc-retainonlydedx", VariantType::Bool, false, {"Keep only dEdx information, zero out everything else"}}, ConfigParamSpec{"trackqc-fraction", VariantType::Float, float(0.1), {"Fraction of tracks to QC"}}, ConfigParamSpec{"trackqc-NTrCut", VariantType::Int64, 4L, {"Minimal length of the track - in amount of tracklets"}}, ConfigParamSpec{"trackqc-tpc-dca", VariantType::Float, 3.f, {"Keep TPC standalone track with this DCAxy to the PV"}}, @@ -3271,7 +3565,7 @@ DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, boo ConfigParamSpec{"trackqc-tpc-pt", VariantType::Float, 0.2f, {"Keep TPC standalone track with this pt"}}, ConfigParamSpec{"with-streamers", VariantType::String, "", {"Bit-mask to steer writing of intermediate streamer files"}}, ConfigParamSpec{"seed", VariantType::Int, 0, {"Set seed for random generator used for sampling (0 (default) means using a random_device)"}}, - }}; + ConfigParamSpec{"mc-signal-filt", VariantType::Bool, false, {"Enable usage of signal filtering (only for MC with embedding)"}}}}; } } // namespace o2::aodproducer diff --git a/Detectors/AOD/src/aod-producer-workflow.cxx b/Detectors/AOD/src/aod-producer-workflow.cxx index 81e178642e403..d75694f3bd512 100644 --- a/Detectors/AOD/src/aod-producer-workflow.cxx +++ b/Detectors/AOD/src/aod-producer-workflow.cxx @@ -18,6 +18,7 @@ #include "DetectorsRaw/HBFUtilsInitializer.h" #include "Framework/CallbacksPolicy.h" #include "DetectorsBase/DPLWorkflowUtils.h" +#include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" using namespace o2::framework; using GID = o2::dataformats::GlobalTrackID; @@ -38,10 +39,12 @@ void customize(std::vector& workflowOptions) {"disable-secondary-vertices", o2::framework::VariantType::Bool, false, {"disable filling secondary vertices"}}, {"disable-strangeness-tracker", o2::framework::VariantType::Bool, false, {"disable filling strangeness tracking"}}, {"enable-FIT-extra", o2::framework::VariantType::Bool, false, {"enable FIT extra output"}}, + {"enable-TRD-extra", o2::framework::VariantType::Bool, false, {"enable TRD extra output"}}, {"info-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of sources to use"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}, {"combine-source-devices", o2::framework::VariantType::Bool, false, {"merge DPL source devices"}}, {"ctpconfig-run-independent", o2::framework::VariantType::Bool, false, {"Use CTP config w/o runNumber tag"}}}; + o2::itsmft::DPLAlpideParamInitializer::addConfigOption(options); o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } @@ -56,6 +59,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) bool enableST = !configcontext.options().get("disable-strangeness-tracker"); bool ctpcfgperrun = !configcontext.options().get("ctpconfig-run-independent"); bool enableFITextra = configcontext.options().get("enable-FIT-extra"); + bool enableTRDextra = configcontext.options().get("enable-TRD-extra"); GID::mask_t allowedSrc = GID::getSourcesMask("ITS,MFT,MCH,MID,MCH-MID,TPC,TRD,ITS-TPC,TPC-TOF,TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD,TPC-TRD-TOF,ITS-TPC-TRD-TOF,MFT-MCH,FT0,FV0,FDD,ZDC,EMC,CTP,PHS,CPV,HMP"); GID::mask_t src = allowedSrc & GID::getSourcesMask(configcontext.options().get("info-sources")); @@ -66,7 +70,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) } WorkflowSpec specs; - specs.emplace_back(o2::aodproducer::getAODProducerWorkflowSpec(src, enableSV, enableST, useMC, ctpcfgperrun, enableFITextra)); + specs.emplace_back(o2::aodproducer::getAODProducerWorkflowSpec(src, enableSV, enableST, useMC, ctpcfgperrun, enableFITextra, enableTRDextra)); auto srcCls = src & ~(GID::getSourceMask(GID::MCH) | GID::getSourceMask(GID::MID)); // Don't read global MID and MCH clusters (those attached to tracks are always read) auto srcMtc = src; diff --git a/Detectors/Align/Workflow/include/AlignmentWorkflow/BarrelAlignmentSpec.h b/Detectors/Align/Workflow/include/AlignmentWorkflow/BarrelAlignmentSpec.h index 197ace2bd9d20..9793b8609874f 100644 --- a/Detectors/Align/Workflow/include/AlignmentWorkflow/BarrelAlignmentSpec.h +++ b/Detectors/Align/Workflow/include/AlignmentWorkflow/BarrelAlignmentSpec.h @@ -21,17 +21,13 @@ using namespace o2::framework; namespace o2 { -namespace tpc -{ -struct CorrectionMapsLoaderGloOpts; -} namespace align { /// create a processor spec framework::DataProcessorSpec getBarrelAlignmentSpec(o2::dataformats::GlobalTrackID::mask_t srcMP, o2::dataformats::GlobalTrackID::mask_t src, - o2::detectors::DetID::mask_t dets, o2::detectors::DetID::mask_t skipDetClusters, bool enableCosmic, int postproc, bool useMC, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts); + o2::detectors::DetID::mask_t dets, o2::detectors::DetID::mask_t skipDetClusters, bool enableCosmic, int postproc, bool useMC); } // namespace align } // namespace o2 diff --git a/Detectors/Align/Workflow/src/BarrelAlignmentSpec.cxx b/Detectors/Align/Workflow/src/BarrelAlignmentSpec.cxx index cae835a99a2aa..3e42c19f535f8 100644 --- a/Detectors/Align/Workflow/src/BarrelAlignmentSpec.cxx +++ b/Detectors/Align/Workflow/src/BarrelAlignmentSpec.cxx @@ -36,8 +36,8 @@ #include "TRDBase/TrackletTransformer.h" #include "CommonUtils/TreeStreamRedirector.h" #include "TPCCalibration/VDriftHelper.h" -#include "TPCCalibration/CorrectionMapsLoader.h" -#include "GPUO2Interface.h" +#include "TPCFastTransformPOD.h" +#include "GPUO2ExternalUser.h" #include "GPUO2InterfaceUtils.h" #include "GPUParam.h" #include "Headers/DataHeader.h" @@ -64,7 +64,7 @@ #include "DataFormatsTPC/ClusterNative.h" #include "DataFormatsTPC/WorkflowHelper.h" #include "ITSBase/GeometryTGeo.h" -#include "ITSMFTBase/DPLAlpideParam.h" +#include "DataFormatsITSMFT/DPLAlpideParam.h" */ using namespace o2::framework; @@ -86,13 +86,9 @@ class BarrelAlignmentSpec : public Task CheckConstaints = 0x1 << 1, GenPedeFiles = 0x1 << 2, LabelPedeResults = 0x1 << 3 }; - BarrelAlignmentSpec(GTrackID::mask_t srcMP, std::shared_ptr dr, std::shared_ptr ggrec, const o2::tpc::CorrectionMapsLoaderGloOpts& tpcOpt, + BarrelAlignmentSpec(GTrackID::mask_t srcMP, std::shared_ptr dr, std::shared_ptr ggrec, DetID::mask_t detmask, bool cosmic, int postprocess, bool useMC, bool loadTPCCalib) - : mDataRequest(dr), mGRPGeomRequest(ggrec), mMPsrc{srcMP}, mDetMask{detmask}, mCosmic(cosmic), mPostProcessing(postprocess), mUseMC(useMC), mLoadTPCCalib(loadTPCCalib) - { - mTPCCorrMapsLoader.setLumiScaleType(tpcOpt.lumiType); - mTPCCorrMapsLoader.setLumiScaleMode(tpcOpt.lumiMode); - } + : mDataRequest(dr), mGRPGeomRequest(ggrec), mMPsrc{srcMP}, mDetMask{detmask}, mCosmic(cosmic), mPostProcessing(postprocess), mUseMC(useMC), mLoadTPCCalib(loadTPCCalib) {} ~BarrelAlignmentSpec() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -121,7 +117,8 @@ class BarrelAlignmentSpec : public Task std::unique_ptr mTPCParam; o2::tpc::VDriftHelper mTPCVDriftHelper{}; - o2::tpc::CorrectionMapsLoader mTPCCorrMapsLoader{}; + + const o2::gpu::TPCFastTransformPOD* mTPCCorrMaps{}; // TStopwatch mTimer; @@ -183,9 +180,6 @@ void BarrelAlignmentSpec::init(InitContext& ic) } mIgnoreCCDBAlignment = ic.options().get("ignore-ccdb-alignment"); if (!mPostProcessing) { - if (mLoadTPCCalib) { - mTPCCorrMapsLoader.init(ic); - } if (GTrackID::includesDet(DetID::TRD, mMPsrc)) { mTRDTransformer.reset(new o2::trd::TrackletTransformer); if (ic.options().get("apply-xor")) { @@ -265,19 +259,16 @@ void BarrelAlignmentSpec::updateTimeDependentParams(ProcessingContext& pc) prevField = newField; if (mDetMask[DetID::TPC]) { mTPCParam.reset(new o2::gpu::GPUParam); - mTPCParam->SetDefaults(o2::base::Propagator::Instance()->getNominalBz()); + mTPCParam->SetDefaults(o2::base::Propagator::Instance()->getNominalBz(), false); mController->setTPCParam(mTPCParam.get()); } } mTPCVDriftHelper.extractCCDBInputs(pc); - mTPCCorrMapsLoader.extractCCDBInputs(pc); - bool updateMaps = false; - if (mTPCCorrMapsLoader.isUpdated()) { - mTPCCorrMapsLoader.acknowledgeUpdate(); - updateMaps = true; - } - mController->setTPCCorrMaps(&mTPCCorrMapsLoader); + + auto const& raw = pc.inputs().get("corrMap"); + mTPCCorrMaps = &o2::gpu::TPCFastTransformPOD::get(raw); + mController->setTPCCorrMaps(mTPCCorrMaps); if (mTPCVDriftHelper.isUpdated()) { LOGP(info, "Updating TPC fast transform map with new VDrift factor of {} wrt reference {} and DriftTimeOffset correction {} wrt {} from source {}", mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, @@ -285,10 +276,6 @@ void BarrelAlignmentSpec::updateTimeDependentParams(ProcessingContext& pc) mTPCVDriftHelper.getSourceName()); mController->setTPCVDrift(mTPCVDriftHelper.getVDriftObject()); mTPCVDriftHelper.acknowledgeUpdate(); - updateMaps = true; - } - if (updateMaps) { - mTPCCorrMapsLoader.updateVDrift(mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, mTPCVDriftHelper.getVDriftObject().getTimeOffset()); } } } @@ -313,9 +300,6 @@ void BarrelAlignmentSpec::finaliseCCDB(o2::framework::ConcreteDataMatcher& match return; } - if (mTPCCorrMapsLoader.accountCCDBInputs(matcher, obj)) { - return; - } } void BarrelAlignmentSpec::run(ProcessingContext& pc) @@ -373,7 +357,7 @@ void BarrelAlignmentSpec::endOfStream(EndOfStreamContext& ec) mDBGOut.reset(); } -DataProcessorSpec getBarrelAlignmentSpec(GTrackID::mask_t srcMP, GTrackID::mask_t src, DetID::mask_t dets, DetID::mask_t skipDetClusters, bool enableCosmic, int postprocess, bool useMC, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts) +DataProcessorSpec getBarrelAlignmentSpec(GTrackID::mask_t srcMP, GTrackID::mask_t src, DetID::mask_t dets, DetID::mask_t skipDetClusters, bool enableCosmic, int postprocess, bool useMC) { std::vector outputs; auto dataRequest = std::make_shared(); @@ -398,7 +382,7 @@ DataProcessorSpec getBarrelAlignmentSpec(GTrackID::mask_t srcMP, GTrackID::mask_ } if (src[DetID::TPC] && !skipDetClusters[DetID::TPC]) { o2::tpc::VDriftHelper::requestCCDBInputs(dataRequest->inputs); - o2::tpc::CorrectionMapsLoader::requestCCDBInputs(dataRequest->inputs, opts, sclOpts); + dataRequest->inputs.emplace_back("corrMap", o2::header::gDataOriginTPC, "TPCCORRMAP", 0, Lifetime::Timeframe); loadTPCCalib = true; } } @@ -416,7 +400,7 @@ DataProcessorSpec getBarrelAlignmentSpec(GTrackID::mask_t srcMP, GTrackID::mask_ "barrel-alignment", dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask(srcMP, dataRequest, ccdbRequest, sclOpts, dets, enableCosmic, postprocess, useMC, loadTPCCalib)}, + AlgorithmSpec{adaptFromTask(srcMP, dataRequest, ccdbRequest, dets, enableCosmic, postprocess, useMC, loadTPCCalib)}, opts}; } diff --git a/Detectors/Align/Workflow/src/barrel-alignment-workflow.cxx b/Detectors/Align/Workflow/src/barrel-alignment-workflow.cxx index 8df479ba39260..07224702b1be1 100644 --- a/Detectors/Align/Workflow/src/barrel-alignment-workflow.cxx +++ b/Detectors/Align/Workflow/src/barrel-alignment-workflow.cxx @@ -20,13 +20,14 @@ #include "TPCReaderWorkflow/ClusterReaderSpec.h" #include "TPCWorkflow/ClusterSharingMapSpec.h" #include "TPCWorkflow/TPCScalerSpec.h" -#include "TPCCalibration/CorrectionMapsLoader.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 "DataFormatsITSMFT/DPLAlpideParamInitializer.h" +#include "TPCCalibration/CorrectionMapsOptions.h" #include "Algorithm/RangeTokenizer.h" #include "DetectorsRaw/HBFUtilsInitializer.h" @@ -59,7 +60,8 @@ void customize(std::vector& workflowOptions) {"enable-cosmic", VariantType::Bool, false, {"enable cosmic tracks)"}}, {"postprocessing", VariantType::Int, 0, {"postprocessing bits: 1 - extract alignment objects, 2 - check constraints, 4 - print mpParams/Constraints, 8 - relabel pede results"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; - o2::tpc::CorrectionMapsLoader::addGlobalOptions(options); + o2::itsmft::DPLAlpideParamInitializer::addITSConfigOption(options); + o2::tpc::CorrectionMapsOptions::addGlobalOptions(options); o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } @@ -102,7 +104,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) if (dets[DetID::TPC]) { loadTPCClusters = loadTPCTracks = true; } - auto sclOpt = o2::tpc::CorrectionMapsLoader::parseGlobalOptions(configcontext.options()); + auto sclOpt = o2::tpc::CorrectionMapsOptions::parseGlobalOptions(configcontext.options()); if (!postprocess) { // this part is needed only if the data should be read if (GID::includesDet(DetID::ITS, src)) { src |= GID::getSourceMask(GID::ITS); @@ -148,11 +150,11 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) o2::conf::ConfigurableParam::writeINI("o2_barrel_alignment_configuration.ini"); } - if (sclOpt.needTPCScalersWorkflow() && !configcontext.options().get("disable-root-input")) { - specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt.lumiType == 2, sclOpt.enableMShapeCorrection)); + if (!configcontext.options().get("disable-root-input")) { + specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt.lumiType == o2::tpc::LumiScaleType::TPCScaler, sclOpt.enableMShapeCorrection, sclOpt)); } - specs.emplace_back(o2::align::getBarrelAlignmentSpec(srcMP, src, dets, skipDetClusters, enableCosmic, postprocess, useMC, sclOpt)); + specs.emplace_back(o2::align::getBarrelAlignmentSpec(srcMP, src, dets, skipDetClusters, enableCosmic, postprocess, useMC)); // RS FIXME: check which clusters are really needed if (!postprocess) { GID::mask_t dummy; diff --git a/Detectors/Align/include/Align/AlignConfig.h b/Detectors/Align/include/Align/AlignConfig.h index 91b503c2c923e..e72d436a14e3b 100644 --- a/Detectors/Align/include/Align/AlignConfig.h +++ b/Detectors/Align/include/Align/AlignConfig.h @@ -85,6 +85,7 @@ struct AlignConfig : public o2::conf::ConfigurableParamHelper { float controlFraction = -1.; // fraction for which control output is requested, if negative - only 1st instance of device will write them float MPRecOutFraction = -1.; // compact Millepede2Record fraction, if negative - only 1st instance of device will write them + bool useLinRef = true; // use initial track for lienarization reference point bool MilleOut = true; // Mille output bool KalmanResid = true; // Kalman residuals bool MilleOutBin = true; // text vs binary output for mille data diff --git a/Detectors/Align/include/Align/AlignableDetectorTRD.h b/Detectors/Align/include/Align/AlignableDetectorTRD.h index a73b0f76902d2..4e7577b11055c 100644 --- a/Detectors/Align/include/Align/AlignableDetectorTRD.h +++ b/Detectors/Align/include/Align/AlignableDetectorTRD.h @@ -18,7 +18,7 @@ #define ALIGNABLEDETECTORTRD_H #include "Align/AlignableDetector.h" -#include "TRDBase/RecoParam.h" +#include "GPUTRDRecoParam.h" namespace o2 { @@ -64,7 +64,7 @@ class AlignableDetectorTRD final : public AlignableDetector int processPoints(GIndex gid, int npntCut, bool inv) final; protected: - o2::trd::RecoParam mRecoParam; // parameters required for TRD reconstruction + o2::gpu::GPUTRDRecoParam mRecoParam; // parameters required for TRD reconstruction double mNonRCCorrDzDtgl = 0.; // correction in Z for non-crossing tracklets double mCorrDVT = 0.; // correction to Vdrift*t double mExtraErrRC[2] = {0., 0.}; // extra errors for RC tracklets diff --git a/Detectors/Align/include/Align/AlignmentTrack.h b/Detectors/Align/include/Align/AlignmentTrack.h index ef4552cb9a37d..cb69f11cbf85c 100644 --- a/Detectors/Align/include/Align/AlignmentTrack.h +++ b/Detectors/Align/include/Align/AlignmentTrack.h @@ -39,6 +39,7 @@ class AlignmentTrack : public trackParam_t, public TObject { public: using trackParam_t = o2::track::TrackParametrizationWithError; + using trackPar_t = o2::track::TrackParametrization; using PropagatorD = o2::base::PropagatorD; using MatCorrType = PropagatorD::MatCorrType; using GTrackID = o2::dataformats::GlobalTrackID; @@ -83,9 +84,9 @@ class AlignmentTrack : public trackParam_t, public TObject // template void copyFrom(const o2::track::TrackParametrizationWithError

& trc); - bool propagateToPoint(trackParam_t& tr, const AlignmentPoint* pnt, double maxStep, double maxSnp = 0.95, MatCorrType mt = MatCorrType::USEMatCorrLUT, track::TrackLTIntegral* tLT = nullptr, int signCorr = 0); - bool propagateParamToPoint(trackParam_t& tr, const AlignmentPoint* pnt, double maxStep = 3, double maxSnp = 0.95, MatCorrType mt = MatCorrType::USEMatCorrLUT, int signCorr = 0); // param only - bool propagateParamToPoint(trackParam_t* trSet, int nTr, const AlignmentPoint* pnt, double maxStep = 3, double maxSnp = 0.95, MatCorrType mt = MatCorrType::USEMatCorrLUT, int signCorr = 0); // params only + bool propagateToPoint(trackParam_t& tr, trackPar_t* linRef, const AlignmentPoint* pnt, double maxStep, double maxSnp = 0.95, MatCorrType mt = MatCorrType::USEMatCorrLUT, track::TrackLTIntegral* tLT = nullptr, int signCorr = 0); + bool propagateParamToPoint(trackPar_t& tr, const AlignmentPoint* pnt, double maxStep = 3, double maxSnp = 0.95, MatCorrType mt = MatCorrType::USEMatCorrLUT, int signCorr = 0); // param only + bool propagateParamToPoint(trackPar_t* trSet, int nTr, const AlignmentPoint* pnt, double maxStep = 3, double maxSnp = 0.95, MatCorrType mt = MatCorrType::USEMatCorrLUT, int signCorr = 0); // params only // bool calcResiduals(const double* params = nullptr); bool calcResidDeriv(double* params = nullptr); @@ -119,23 +120,23 @@ class AlignmentTrack : public trackParam_t, public TObject 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); + bool applyMatCorr(trackPar_t& trPar, const double* corrDiag, const AlignmentPoint* pnt); + bool applyMatCorr(trackPar_t* trSet, int ntr, const double* corrDiaf, const AlignmentPoint* pnt); + bool applyMatCorr(trackPar_t& trPar, const double* corrpar); // double getResidual(int dim, int pntID) const { return mResid[dim][pntID]; } const double* getDResDLoc(int dim, int pntID) const { return mDResDLoc[dim].data() + (pntID * mNLocPar); } const double* getDResDGlo(int dim, int id) const { return mDResDGlo[dim].data() + id; } const int* getGloParID() const { return mGloParID.data(); } // - 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 setParams(trackPar_t& tr, double x, double alp, const double* par, bool add); + void setParams(trackPar_t* trSet, int ntr, double x, double alp, const double* par, bool add); + void setParam(trackPar_t& tr, int par, double val); + void setParam(trackPar_t* trSet, int ntr, int par, double val); + void modParam(trackPar_t& tr, int par, double delta); + void modParam(trackPar_t* trSet, int ntr, int par, double delta); // - void richardsonDeriv(const trackParam_t* trSet, const double* delta, + void richardsonDeriv(const trackPar_t* trSet, const double* delta, const AlignmentPoint* pnt, double& derY, double& derZ); // const double* getLocPars() const { return mLocPar.data(); } @@ -179,13 +180,14 @@ class AlignmentTrack : public trackParam_t, public TObject std::vector mLocPar; // local parameters array std::vector mGloParID; // IDs of relevant global params private: - bool propagate(trackParam_t& tr, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, track::TrackLTIntegral* tLT, int signCorr = 0); + bool propagate(trackParam_t& tr, trackPar_t* linRef, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, track::TrackLTIntegral* tLT, int signCorr = 0); + bool propagate(trackPar_t& tr, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, track::TrackLTIntegral* tLT, int signCorr = 0); // ClassDefOverride(AlignmentTrack, 2) }; //____________________________________________________________________________________________ -inline void AlignmentTrack::setParams(trackParam_t& tr, double x, double alp, const double* par, bool add) +inline void AlignmentTrack::setParams(trackPar_t& tr, double x, double alp, const double* par, bool add) { // set track params const double kDefQ2PtCosm = 1; @@ -205,7 +207,7 @@ inline void AlignmentTrack::setParams(trackParam_t& tr, double x, double alp, co } //____________________________________________________________________________________________ -inline void AlignmentTrack::setParams(trackParam_t* trSet, int ntr, double x, double alp, const double* par, bool add) +inline void AlignmentTrack::setParams(trackPar_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 @@ -224,14 +226,14 @@ inline void AlignmentTrack::setParams(trackParam_t* trSet, int ntr, double x, do } //____________________________________________________________________________________________ -inline void AlignmentTrack::setParam(trackParam_t& tr, int par, double val) +inline void AlignmentTrack::setParam(trackPar_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) +inline void AlignmentTrack::setParam(trackPar_t* trSet, int ntr, int par, double val) { // set parames for multiple tracks (VECTORIZE THIS) for (int i = 0; i < ntr; ++i) { @@ -240,7 +242,7 @@ inline void AlignmentTrack::setParam(trackParam_t* trSet, int ntr, int par, doub } //____________________________________________________________________________________________ -inline void AlignmentTrack::modParam(trackParam_t& tr, int par, double delta) +inline void AlignmentTrack::modParam(trackPar_t& tr, int par, double delta) { // modify track parameter const auto val = tr.getParam(par) + delta; @@ -248,7 +250,7 @@ inline void AlignmentTrack::modParam(trackParam_t& tr, int par, double delta) } //____________________________________________________________________________________________ -inline void AlignmentTrack::modParam(trackParam_t* trSet, int ntr, int par, double delta) +inline void AlignmentTrack::modParam(trackPar_t* trSet, int ntr, int par, double delta) { // modify track parameter (VECTORIZE THOS) for (int i = 0; i < ntr; ++i) { diff --git a/Detectors/Align/include/Align/Controller.h b/Detectors/Align/include/Align/Controller.h index 96ee2e4fcf418..a9c4eac734535 100644 --- a/Detectors/Align/include/Align/Controller.h +++ b/Detectors/Align/include/Align/Controller.h @@ -30,7 +30,7 @@ #include "ReconstructionDataFormats/PrimaryVertex.h" #include "ReconstructionDataFormats/TrackCosmics.h" #include "DataFormatsTPC/VDriftCorrFact.h" -#include "CorrectionMapsHelper.h" +#include "TPCFastTransformPOD.h" #include "Align/Millepede2Record.h" #include "Align/ResidualsController.h" @@ -54,7 +54,7 @@ #include #include #include "Align/Mille.h" -// #include "GPUO2Interface.h" +// #include "GPUO2ExternalUser.h" // #include "DataFormatsTPC/WorkflowHelper.h" namespace o2 @@ -272,8 +272,8 @@ class Controller final : public TObject bool getAllowAfterburnerTracks() const { return mAllowAfterburnerTracks; } void setTPCVDrift(const o2::tpc::VDriftCorrFact& v); - void setTPCCorrMaps(o2::gpu::CorrectionMapsHelper* maph); - o2::gpu::CorrectionMapsHelper* getTPCCorrMaps() { return mTPCCorrMapsHelper; } + void setTPCCorrMaps(const o2::gpu::TPCFastTransformPOD* maph); + const o2::gpu::TPCFastTransformPOD* getTPCCorrMaps() { return mTPCCorrMaps; } const o2::tpc::VDriftCorrFact& getTPCVDrift() const { return mTPCDrift; } int getInstanceID() const { return mInstanceID; } @@ -359,7 +359,7 @@ class Controller final : public TObject bool mUseRecoOCDB = true; // flag to preload reco-time calib objects o2::tpc::VDriftCorrFact mTPCDrift{}; - o2::gpu::CorrectionMapsHelper* mTPCCorrMapsHelper = nullptr; + const o2::gpu::TPCFastTransformPOD* mTPCCorrMaps = nullptr; // static const int sSkipLayers[kNLrSkip]; // detector layers for which we don't need module matrices diff --git a/Detectors/Align/src/AlignableDetectorTPC.cxx b/Detectors/Align/src/AlignableDetectorTPC.cxx index f66d9e3f3ab95..980ded2d8ff2f 100644 --- a/Detectors/Align/src/AlignableDetectorTPC.cxx +++ b/Detectors/Align/src/AlignableDetectorTPC.cxx @@ -24,7 +24,7 @@ #include "DataFormatsTPC/WorkflowHelper.h" #include #include -#include "GPUO2Interface.h" +#include "GPUO2ExternalUser.h" #include "DataFormatsTPC/WorkflowHelper.h" #include "GPUParam.inc" @@ -214,8 +214,8 @@ int AlignableDetectorTPC::processPoints(GIndex gid, int npntCut, bool inv) auto* sectSensor = (AlignableSensorTPC*)getSensor(currentSector); const auto* sysE = sectSensor->getAddError(); // additional syst error - gpu::gpustd::array p = {y, z}; - gpu::gpustd::array c = {0, 0, 0}; + std::array p = {y, z}; + std::array c = {0, 0, 0}; mController->getTPCParam()->GetClusterErrors2(sector, currentRow, z, trkParam.getSnp(), trkParam.getTgl(), -1.f, 0.f, 0.f, c[0], c[2]); // TODO: Note this disables occupancy / charge components of the error estimation mController->getTPCParam()->UpdateClusterError2ByState(clusterState, c[0], c[2]); int nrComb = std::abs(row - currentRow) + 1; diff --git a/Detectors/Align/src/AlignableDetectorTRD.cxx b/Detectors/Align/src/AlignableDetectorTRD.cxx index d752553bf6ead..6fe8a60ef90f6 100644 --- a/Detectors/Align/src/AlignableDetectorTRD.cxx +++ b/Detectors/Align/src/AlignableDetectorTRD.cxx @@ -26,6 +26,7 @@ #include "DataFormatsTRD/TrackTRD.h" #include "DataFormatsTRD/Tracklet64.h" #include "DataFormatsTRD/CalibratedTracklet.h" +#include "GPUO2InterfaceConfiguration.h" #include #include @@ -175,10 +176,10 @@ int AlignableDetectorTRD::processPoints(GIndex gid, int npntCut, bool inv) return -1; } auto propagator = o2::base::Propagator::Instance(); // float version! - static float prevBz = -99999.; - if (prevBz != propagator->getNominalBz()) { - prevBz = propagator->getNominalBz(); - mRecoParam.setBfield(prevBz); + static bool firstCall = true; + if (firstCall) { + mRecoParam.init(propagator->getNominalBz()); + firstCall = false; } const auto* transformer = mController->getTRDTransformer(); auto algTrack = mController->getAlgTrack(); diff --git a/Detectors/Align/src/AlignmentTrack.cxx b/Detectors/Align/src/AlignmentTrack.cxx index 554d30e246e29..644ee07c64984 100644 --- a/Detectors/Align/src/AlignmentTrack.cxx +++ b/Detectors/Align/src/AlignmentTrack.cxx @@ -168,7 +168,7 @@ bool AlignmentTrack::calcResidDeriv(double* extendedParams, bool invert, int pFr // (like http://root.cern.ch/root/html/ROOT__Math__RichardsonDerivator.html) // const auto& algConf = AlignConfig::Instance(); - trackParam_t probD[kNRDClones]; // use this to vary supplied param for derivative calculation + trackPar_t probD[kNRDClones]; // use this to vary supplied param for derivative calculation double varDelta[kRichardsonN]; const int kInvElem[kNKinParBON] = {-1, 1, 1, -1, -1}; // @@ -511,7 +511,7 @@ bool AlignmentTrack::calcResiduals(const double* extendedParams, bool invert, in } //______________________________________________________ -bool AlignmentTrack::propagateParamToPoint(trackParam_t* tr, int nTr, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, int signCorr) +bool AlignmentTrack::propagateParamToPoint(trackPar_t* tr, int nTr, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, int signCorr) { // Propagate set of tracks to the point (only parameters, no error matrix) // VECTORIZE this @@ -521,7 +521,7 @@ bool AlignmentTrack::propagateParamToPoint(trackParam_t* tr, int nTr, const Alig if (!propagateParamToPoint(tr[itr], pnt, maxStep, maxSnp, mt, signCorr)) { if (algConf.verbose > 2) { LOG(error) << "Failed on clone " << itr << " propagation "; - tr[itr].print(); + tr[itr].printParam(); pnt->print(AlignmentPoint::kMeasurementBit | AlignmentPoint::kMaterialBit); } return false; @@ -531,21 +531,33 @@ bool AlignmentTrack::propagateParamToPoint(trackParam_t* tr, int nTr, const Alig } //______________________________________________________ -bool AlignmentTrack::propagateParamToPoint(trackParam_t& tr, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, int signCorr) +bool AlignmentTrack::propagateParamToPoint(trackPar_t& tr, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, int signCorr) { // propagate tracks to the point (only parameters, no error matrix) return propagate(tr, pnt, maxStep, maxSnp, mt, nullptr, signCorr); } //______________________________________________________ -bool AlignmentTrack::propagateToPoint(trackParam_t& tr, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, track::TrackLTIntegral* tLT, int signCorr) +bool AlignmentTrack::propagateToPoint(trackParam_t& tr, trackPar_t* linRef, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, track::TrackLTIntegral* tLT, int signCorr) { // 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, signCorr); + return propagate(tr, linRef, pnt, maxStep, maxSnp, mt, tLT, signCorr); } -bool AlignmentTrack::propagate(trackParam_t& track, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, track::TrackLTIntegral* tLT, int signCorr) +bool AlignmentTrack::propagate(trackParam_t& track, trackPar_t* linRef, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, track::TrackLTIntegral* tLT, int signCorr) +{ + if (signCorr == 0) { // auto + // calculate the sign of the energy loss correction and ensure the upper leg of cosmics is calculated correctly. + double dx = pnt->getXTracking() - track.getX(); + int dir = dx > 0.f ? 1 : -1; + signCorr = pnt->isInvDir() ? dir : -dir; // propagation along the track direction should have signCorr=-1 + } + // do propagation in at least 2 step to reveal eventual effect of MS on the position + return PropagatorD::Instance()->propagateToAlphaX(track, linRef, pnt->getAlphaSens(), pnt->getXTracking(), pnt->getUseBzOnly(), maxSnp, maxStep, 2, mt, tLT, signCorr); +} + +bool AlignmentTrack::propagate(trackPar_t& track, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, track::TrackLTIntegral* tLT, int signCorr) { if (signCorr == 0) { // auto // calculate the sign of the energy loss correction and ensure the upper leg of cosmics is calculated correctly. @@ -603,7 +615,7 @@ bool AlignmentTrack::ApplyMS(trackParam_t& trPar, double tms,double pms) */ //______________________________________________________ -bool AlignmentTrack::applyMatCorr(trackParam_t& trPar, const double* corrPar, const AlignmentPoint* pnt) +bool AlignmentTrack::applyMatCorr(trackPar_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 @@ -630,7 +642,7 @@ bool AlignmentTrack::applyMatCorr(trackParam_t& trPar, const double* corrPar, co } //______________________________________________________ -bool AlignmentTrack::applyMatCorr(trackParam_t& trPar, const double* corr) +bool AlignmentTrack::applyMatCorr(trackPar_t& trPar, const double* corr) { // Modify track param (e.g. trackParam_t) in the tracking frame // by delta accounting for material effects @@ -645,7 +657,7 @@ bool AlignmentTrack::applyMatCorr(trackParam_t& trPar, const double* corr) printf("%+.3e ", corr[i]); } printf("\n"); - trPar.print(); + trPar.printParam(); } return false; } @@ -656,7 +668,7 @@ bool AlignmentTrack::applyMatCorr(trackParam_t& trPar, const double* corr) } //______________________________________________________ -bool AlignmentTrack::applyMatCorr(trackParam_t* trSet, int ntr, const double* corrDiag, const AlignmentPoint* pnt) +bool AlignmentTrack::applyMatCorr(trackPar_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 @@ -683,7 +695,7 @@ bool AlignmentTrack::applyMatCorr(trackParam_t* trSet, int ntr, const double* co if (!applyMatCorr(trSet[itr], corr)) { if (algConf.verbose > 2) { LOGP(error, "Failed on clone {} materials", itr); - trSet[itr].print(); + trSet[itr].printParam(); } return false; } @@ -732,7 +744,7 @@ double AlignmentTrack::richardsonExtrap(const double* val, int ord) } //______________________________________________ -void AlignmentTrack::richardsonDeriv(const trackParam_t* trSet, const double* delta, const AlignmentPoint* pnt, double& derY, double& derZ) +void AlignmentTrack::richardsonDeriv(const trackPar_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] @@ -882,7 +894,7 @@ bool AlignmentTrack::iniFit() // // propagate to reference point, which is the inner point of lower leg const AlignmentPoint* refP = getPoint(getInnerPointID()); - if (!propagateToPoint(trcU, refP, algConf.maxStep, algConf.maxSnp, MatCorrType(algConf.matCorType), nullptr, -1)) { // moving along the track: energy is lost + if (!propagateToPoint(trcU, nullptr, refP, algConf.maxStep, algConf.maxSnp, MatCorrType(algConf.matCorType), nullptr, -1)) { // moving along the track: energy is lost return false; } // @@ -1024,6 +1036,7 @@ bool AlignmentTrack::fitLeg(trackParam_t& trc, int pFrom, int pTo, bool& inv) } return false; } + trackPar_t linRef(trc), *linRefP = algConf.useLinRef ? &linRef : nullptr; trc.setCov(kIniErr); trc.setCov(16 * trc.getQ2Pt() * trc.getQ2Pt(), 4, 4); // lowest diagonal element (Q2Pt2) // @@ -1042,7 +1055,7 @@ bool AlignmentTrack::fitLeg(trackParam_t& trc, int pFrom, int pTo, bool& inv) int pntCnt = 0; for (int ip = pFrom; ip != pTo; ip += pinc) { // inward fit from outer point AlignmentPoint* pnt = getPoint(ip); - if (!propagateToPoint(trc, pnt, algConf.maxStep, algConf.maxSnp, MatCorrType(algConf.matCorType), nullptr, signELoss)) { // against track direction : e.loss is compensated + if (!propagateToPoint(trc, linRefP, pnt, algConf.maxStep, algConf.maxSnp, MatCorrType(algConf.matCorType), nullptr, signELoss)) { // against track direction : e.loss is compensated if (algConf.verbose > 2) { LOGF(warn, "Failed on propagateToPoint %d (%d : %d) %f", ip, pFrom, pTo, pnt->getXTracking()); trc.print(); @@ -1139,7 +1152,7 @@ bool AlignmentTrack::residKalman() trc.invert(); inv = !inv; } - if (!propagateToPoint(trc, pnt, algConf.maxStep, algConf.maxSnp, MatCorrType(algConf.matCorType), nullptr, signELoss)) { + if (!propagateToPoint(trc, nullptr, pnt, algConf.maxStep, algConf.maxSnp, MatCorrType(algConf.matCorType), nullptr, signELoss)) { return false; } if (!pnt->containsMeasurement()) { @@ -1178,7 +1191,7 @@ bool AlignmentTrack::residKalman() trc.invert(); inv = !inv; } - if (!propagateToPoint(trc, pnt, algConf.maxStep, algConf.maxSnp, MatCorrType(algConf.matCorType), nullptr, signELoss)) { // we are going along track direction, e.loss is applied + if (!propagateToPoint(trc, nullptr, pnt, algConf.maxStep, algConf.maxSnp, MatCorrType(algConf.matCorType), nullptr, signELoss)) { // we are going along track direction, e.loss is applied return false; } if (!pnt->containsMeasurement()) { @@ -1335,7 +1348,7 @@ bool AlignmentTrack::processMaterials(trackParam_t& trc, int pFrom, int pTo) // matTL.clearFast(); // printf("-> ProcMat %d (%d->%d)\n",ip,pFrom,pTo); - if (!propagateToPoint(trc, pnt, algConf.maxStep, algConf.maxSnp, MatCorrType(algConf.matCorType), &matTL, signELoss)) { // with material corrections + if (!propagateToPoint(trc, nullptr, pnt, algConf.maxStep, algConf.maxSnp, MatCorrType(algConf.matCorType), &matTL, signELoss)) { // with material corrections if (algConf.verbose > 2) { LOG(error) << "Failed to take track to point" << ip << " (dir: " << pFrom << "->" << pTo << ") with mat.corr."; trc.print(); @@ -1346,7 +1359,7 @@ bool AlignmentTrack::processMaterials(trackParam_t& trc, int pFrom, int pTo) // // is there enough material to consider the point as a scatterer? bool hasMaterial = matTL.getX2X0() > minX2X0; - if (!propagateToPoint(tr0, pnt, algConf.maxStep, algConf.maxSnp, MatCorrType::USEMatCorrNONE, nullptr, signELoss)) { // no material corrections + if (!propagateToPoint(tr0, nullptr, pnt, algConf.maxStep, algConf.maxSnp, MatCorrType::USEMatCorrNONE, nullptr, signELoss)) { // no material corrections if (algConf.verbose > 2) { LOG(error) << "Failed to take track to point" << ip << " (dir: " << pFrom << "->" << pTo << ") with mat.corr."; tr0.print(); diff --git a/Detectors/Align/src/Controller.cxx b/Detectors/Align/src/Controller.cxx index a45314b2285c0..5f55d07893d33 100644 --- a/Detectors/Align/src/Controller.cxx +++ b/Detectors/Align/src/Controller.cxx @@ -44,7 +44,7 @@ #include #include #include -#include "GPUO2Interface.h" +#include "GPUO2ExternalUser.h" #include "DataFormatsTPC/WorkflowHelper.h" #include #include "CommonUtils/NameConf.h" @@ -1882,9 +1882,9 @@ void Controller::setTPCVDrift(const o2::tpc::VDriftCorrFact& v) } //______________________________________________ -void Controller::setTPCCorrMaps(o2::gpu::CorrectionMapsHelper* maph) +void Controller::setTPCCorrMaps(const o2::gpu::TPCFastTransformPOD* maph) { - mTPCCorrMapsHelper = maph; + mTPCCorrMaps = maph; } } // namespace align diff --git a/Detectors/Base/CMakeLists.txt b/Detectors/Base/CMakeLists.txt index 0ba2905ab02ec..83a9193274e4f 100644 --- a/Detectors/Base/CMakeLists.txt +++ b/Detectors/Base/CMakeLists.txt @@ -8,6 +8,7 @@ # In applying this license CERN does not waive the privileges and immunities # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +#add_compile_options(-O0 -g -fPIC) o2_add_library(DetectorsBase SOURCES src/Detector.cxx @@ -28,6 +29,8 @@ o2_add_library(DetectorsBase src/Stack.cxx src/VMCSeederService.cxx src/GlobalParams.cxx + src/O2Tessellated.cxx + src/TGeoGeometryUtils.cxx PUBLIC_LINK_LIBRARIES FairRoot::Base O2::CommonUtils O2::DetectorsCommonDataFormats @@ -45,6 +48,7 @@ o2_add_library(DetectorsBase O2::GPUDataTypes MC::VMC TBB::tbb + ROOT::Gdml ) o2_target_root_dictionary(DetectorsBase @@ -61,7 +65,9 @@ o2_target_root_dictionary(DetectorsBase include/DetectorsBase/Aligner.h include/DetectorsBase/Stack.h include/DetectorsBase/SimFieldUtils.h - include/DetectorsBase/GlobalParams.h) + include/DetectorsBase/GlobalParams.h + include/DetectorsBase/O2Tessellated.h + ) if(BUILD_SIMULATION) if (NOT APPLE) @@ -87,6 +93,7 @@ endif() install(FILES test/buildMatBudLUT.C test/extractLUTLayers.C + test/rescaleLUT.C DESTINATION share/macro/) o2_add_test_root_macro(test/buildMatBudLUT.C @@ -96,3 +103,7 @@ o2_add_test_root_macro(test/buildMatBudLUT.C o2_add_test_root_macro(test/extractLUTLayers.C PUBLIC_LINK_LIBRARIES O2::DetectorsBase LABELS detectorsbase) + +o2_add_test_root_macro(test/rescaleLUT.C + PUBLIC_LINK_LIBRARIES O2::DetectorsBase + LABELS detectorsbase) diff --git a/Detectors/Base/include/DetectorsBase/CTFCoderBase.h b/Detectors/Base/include/DetectorsBase/CTFCoderBase.h index bf4f37ecbeff5..e94123bb2b7ff 100644 --- a/Detectors/Base/include/DetectorsBase/CTFCoderBase.h +++ b/Detectors/Base/include/DetectorsBase/CTFCoderBase.h @@ -58,8 +58,8 @@ class CTFCoderBase Decoder }; CTFCoderBase() = delete; - CTFCoderBase(int n, DetID det, float memFactor = 1.f) : mCoders(n), mDet(det), mMemMarginFactor(memFactor > 1.f ? memFactor : 1.f) {} - CTFCoderBase(OpType op, int n, DetID det, float memFactor = 1.f) : mOpType(op), mCoders(n), mDet(det), mMemMarginFactor(memFactor > 1.f ? memFactor : 1.f) {} + CTFCoderBase(int n, DetID det, float memFactor = 1.f, const std::string& ctfdictOpt = "none") : mCoders(n), mDet(det), mMemMarginFactor(memFactor > 1.f ? memFactor : 1.f), mDictOpt{ctfdictOpt} {} + CTFCoderBase(OpType op, int n, DetID det, float memFactor = 1.f, const std::string& ctfdictOpt = "none") : mOpType(op), mCoders(n), mDet(det), mMemMarginFactor(memFactor > 1.f ? memFactor : 1.f), mDictOpt{ctfdictOpt} {} virtual ~CTFCoderBase() = default; virtual void createCoders(const std::vector& bufVec, o2::ctf::CTFCoderBase::OpType op) = 0; @@ -189,6 +189,7 @@ class CTFCoderBase std::vector loadDictionaryFromTree(TTree* tree); std::vector mCoders; // encoders/decoders DetID mDet; + std::string mDictOpt{}; std::string mDictBinding{"ctfdict"}; std::string mTrigOffsBinding{"trigoffset"}; CTFDictHeader mExtHeader; // external dictionary header @@ -313,6 +314,7 @@ void CTFCoderBase::init(o2::framework::InitContext& ic) if (ic.options().hasOption("irframe-shift")) { mIRFrameSelShift = (long)ic.options().get("irframe-shift"); } + bool ansVersionProvided = false; if (ic.options().hasOption("ans-version")) { if (ic.options().isSet("ans-version")) { const std::string ansVersionString = ic.options().get("ans-version"); @@ -322,18 +324,21 @@ void CTFCoderBase::init(o2::framework::InitContext& ic) if (mANSVersion == ANSVersionUnspecified) { throw std::invalid_argument(fmt::format("Invalid ANS Version {}", ansVersionString)); } + ansVersionProvided = true; } } } - auto dict = ic.options().get("ctf-dict"); - if (dict.empty() || dict == "ccdb") { // load from CCDB + if (mDictOpt.empty() || mDictOpt == "ccdb") { // load from CCDB mLoadDictFromCCDB = true; } else { - if (dict != "none") { // none means per-CTF dictionary will created on the fly - createCodersFromFile(dict, mOpType); - LOGP(info, "Loaded {} from {}", mExtHeader.asString(), dict); + if (mDictOpt != "none") { // none means per-CTF dictionary will created on the fly + createCodersFromFile(mDictOpt, mOpType); + LOGP(info, "Loaded {} from {}, ANS Version {}", mExtHeader.asString(), mDictOpt, std::string(mANSVersion)); } else { - LOGP(info, "Internal per-TF CTF Dict will be created"); + if (!ansVersionProvided) { + mANSVersion = ANSVersion1; + } + LOGP(info, "Internal per-TF CTF Dict will be created, ANS Version {}", std::string(mANSVersion)); } mLoadDictFromCCDB = false; // don't try to load from CCDB } @@ -368,7 +373,7 @@ bool CTFCoderBase::finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, voi } createCoders(*dict, mOpType); mExtHeader = static_cast(CTF::get(dict->data())->getHeader()); - LOGP(info, "Loaded {} from CCDB", mExtHeader.asString()); + LOGP(info, "Loaded {} from CCDB, ANS Version {}", mExtHeader.asString(), std::string(mANSVersion)); } mLoadDictFromCCDB = false; // we read the dictionary at most once! } else if ((match = (matcher == o2::framework::ConcreteDataMatcher("CTP", "Trig_Offset", 0)))) { diff --git a/Detectors/Base/include/DetectorsBase/GeometryManagerParam.h b/Detectors/Base/include/DetectorsBase/GeometryManagerParam.h index c41d41e25e233..b82d526344646 100644 --- a/Detectors/Base/include/DetectorsBase/GeometryManagerParam.h +++ b/Detectors/Base/include/DetectorsBase/GeometryManagerParam.h @@ -23,6 +23,8 @@ struct GeometryManagerParam : public o2::conf::ConfigurableParamHelpermLayers[i]; } - MatLayerCylSet* extractCopy(float rmin, float rmax, float tol = 1e-3) const; + MatLayerCylSet* extractCopy(float rmin, float rmax, float tol = 1e-3, const MatLayerCylSet* toAdd = nullptr) const; void finalizeStructures(); #endif // !GPUCA_ALIGPUCODE @@ -98,6 +98,10 @@ class MatLayerCylSet : public o2::gpu::FlatObject // get material budget traversed on the line between point0 and point1 return getMatBudget(point0.X(), point0.Y(), point0.Z(), point1.X(), point1.Y(), point1.Z()); } + + void scaleLayersByID(int lrFrom, int lrTo, float factor, bool _x2x0 = true, bool _rho = true); + void scaleLayersByR(float rFrom, float rTo, float factor, bool _x2x0 = true, bool _rho = true); + #endif // !GPUCA_ALIGPUCODE GPUd() MatBudget getMatBudget(float x0, float y0, float z0, float x1, float y1, float z1) const; diff --git a/Detectors/Base/include/DetectorsBase/MaterialManager.h b/Detectors/Base/include/DetectorsBase/MaterialManager.h index 4448998ee3d33..b0de75c2d6c84 100644 --- a/Detectors/Base/include/DetectorsBase/MaterialManager.h +++ b/Detectors/Base/include/DetectorsBase/MaterialManager.h @@ -218,7 +218,7 @@ class MaterialManager std::unordered_map mDensityMap; void initDensityMap(); - float getDensity(std::string const& modname); + float getDensity(std::string const& modname, std::string const& matname); // Hide details by providing these private methods so it cannot happen that special settings // are applied as default settings by accident using a boolean flag diff --git a/Detectors/Base/include/DetectorsBase/O2Tessellated.h b/Detectors/Base/include/DetectorsBase/O2Tessellated.h new file mode 100644 index 0000000000000..0a1cee8b3e01f --- /dev/null +++ b/Detectors/Base/include/DetectorsBase/O2Tessellated.h @@ -0,0 +1,142 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_BASE_O2TESSELLATED_ +#define ALICEO2_BASE_O2TESSELLATED_ + +#include "TGeoShape.h" +#include "TGeoBBox.h" +#include "TGeoVector3.h" +#include "TGeoTypedefs.h" +#include "TGeoTessellated.h" + +namespace o2 +{ +namespace base +{ + +class O2Tessellated : public TGeoBBox +{ + + public: + using Vertex_t = Tessellated::Vertex_t; + + private: + int fNfacets = 0; // Number of facets + int fNvert = 0; // Number of vertices + int fNseg = 0; // Number of segments + bool fDefined = false; //! Shape fully defined + bool fClosedBody = false; // The faces are making a closed body + + // for now separate vectors but might be better to group per face + std::vector fVertices; // List of vertices + std::vector fFacets; // List of facets + std::vector fOutwardNormals; // Vector of outward-facing normals (to be streamed !) + + std::multimap fVerticesMap; //! Temporary map used to deduplicate vertices + bool fIsClosed = false; //! to know if shape still needs closure/initialization + void* fBVH = nullptr; //! BVH acceleration structure for safety and navigation + + O2Tessellated(const O2Tessellated&) = delete; + O2Tessellated& operator=(const O2Tessellated&) = delete; + + // bvh helper functions + void BuildBVH(); + void CalculateNormals(); + + public: + // constructors + O2Tessellated() {} + O2Tessellated(const char* name, int nfacets = 0); + O2Tessellated(const char* name, const std::vector& vertices); + // from a TGeoTessellated + O2Tessellated(TGeoTessellated const&, bool check = false); + + // destructor + ~O2Tessellated() override {} + + void ComputeBBox() override; + void CloseShape(bool check = true, bool fixFlipped = true, bool verbose = true); + + bool AddFacet(const Vertex_t& pt0, const Vertex_t& pt1, const Vertex_t& pt2); + bool AddFacet(const Vertex_t& pt0, const Vertex_t& pt1, const Vertex_t& pt2, const Vertex_t& pt3); + bool AddFacet(int i1, int i2, int i3); + bool AddFacet(int i1, int i2, int i3, int i4); + int AddVertex(const Vertex_t& vert); + + bool FacetCheck(int ifacet) const; + Vertex_t FacetComputeNormal(int ifacet, bool& degenerated) const; + + int GetNfacets() const { return fFacets.size(); } + int GetNsegments() const { return fNseg; } + int GetNvertices() const { return fNvert; } + bool IsClosedBody() const { return fClosedBody; } + bool IsDefined() const { return fDefined; } + + const TGeoFacet& GetFacet(int i) const { return fFacets[i]; } + const Vertex_t& GetVertex(int i) const { return fVertices[i]; } + + int DistancetoPrimitive(int, int) override { return 99999; } + const TBuffer3D& GetBuffer3D(int reqSections, Bool_t localFrame) const override; + void GetMeshNumbers(int& nvert, int& nsegs, int& npols) const override; + int GetNmeshVertices() const override { return fNvert; } + void InspectShape() const override {} + TBuffer3D* MakeBuffer3D() const override; + void Print(Option_t* option = "") const override; + void SavePrimitive(std::ostream&, Option_t*) override {} + void SetPoints(double* points) const override; + void SetPoints(Float_t* points) const override; + void SetSegsAndPols(TBuffer3D& buff) const override; + void Sizeof3D() const override {} + + /// Resize and center the shape in a box of size maxsize + void ResizeCenter(double maxsize); + + /// Flip all facets + void FlipFacets() + { + for (auto facet : fFacets) + facet.Flip(); + } + + bool CheckClosure(bool fixFlipped = true, bool verbose = true); + + /// Reader from .obj format + static O2Tessellated* ImportFromObjFormat(const char* objfile, bool check = false, bool verbose = false); + + // navigation functions used by TGeoNavigator (attention: only the iact == 3 cases implemented for now) + Double_t DistFromOutside(const Double_t* point, const Double_t* dir, Int_t iact = 1, + Double_t step = TGeoShape::Big(), Double_t* safe = nullptr) const override; + Double_t DistFromInside(const Double_t* point, const Double_t* dir, Int_t iact = 1, Double_t step = TGeoShape::Big(), + Double_t* safe = nullptr) const override; + bool Contains(const Double_t* point) const override; + Double_t Safety(const Double_t* point, Bool_t in = kTRUE) const override; + void ComputeNormal(const Double_t* point, const Double_t* dir, Double_t* norm) const override; + + // these are trivial implementations, just for debugging + Double_t DistFromInside_Loop(const Double_t* point, const Double_t* dir) const; + Double_t DistFromOutside_Loop(const Double_t* point, const Double_t* dir) const; + bool Contains_Loop(const Double_t* point) const; + + Double_t Capacity() const override; + + private: + // a safety kernel used in multiple implementations + template + Double_t SafetyKernel(const Double_t* point, bool in, int* closest_facet_id = nullptr) const; + + ClassDefOverride(O2Tessellated, 1) // tessellated shape class +}; + +} // namespace base +} // namespace o2 + +#endif diff --git a/Detectors/Base/include/DetectorsBase/Propagator.h b/Detectors/Base/include/DetectorsBase/Propagator.h index a9e2ce6e0383d..75b9446aebade 100644 --- a/Detectors/Base/include/DetectorsBase/Propagator.h +++ b/Detectors/Base/include/DetectorsBase/Propagator.h @@ -17,7 +17,6 @@ #define ALICEO2_BASE_PROPAGATOR_ #include "GPUCommonRtypes.h" -#include "GPUCommonArray.h" #include "CommonConstants/PhysicsConstants.h" #include "ReconstructionDataFormats/Track.h" #include "ReconstructionDataFormats/DCA.h" @@ -25,6 +24,7 @@ #include "DetectorsBase/MatLayerCylSet.h" #ifndef GPUCA_GPUCODE +#include #include #endif @@ -76,6 +76,10 @@ class PropagatorImpl 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(TrackParCov_t& track, TrackPar_t& linRef, 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; @@ -84,6 +88,10 @@ class PropagatorImpl 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 propagateToX(TrackParCov_t& track, TrackPar_t& linRef, 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; + 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; @@ -92,13 +100,40 @@ class PropagatorImpl 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); + return bzOnly ? propagateToX(track, x, getBz(track.getXYZGlo()), maxSnp, maxStep, matCorr, tofInfo, signCorr) : PropagateToXBxByBz(track, x, maxSnp, maxStep, matCorr, tofInfo, signCorr); + } + + GPUd() bool propagateToX(TrackParCov_t& track, TrackPar_t* linRef, 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 + { + return linRef ? propagateToX(track, *linRef, x, bZ, maxSnp, maxStep, matCorr, tofInfo, signCorr) : propagateToX(track, x, bZ, maxSnp, maxStep, matCorr, tofInfo, signCorr); + } + + GPUd() bool PropagateToXBxByBz(TrackParCov_t& track, TrackPar_t* linRef, 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 + { + return linRef ? PropagateToXBxByBz(track, *linRef, x, maxSnp, maxStep, matCorr, tofInfo, signCorr) : PropagateToXBxByBz(track, x, maxSnp, maxStep, matCorr, tofInfo, signCorr); + } + + GPUd() bool propagateTo(TrackParCov_t& track, TrackPar_t* linRef, 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, linRef, x, getBz(track.getXYZGlo()), maxSnp, maxStep, matCorr, tofInfo, signCorr) : PropagateToXBxByBz(track, linRef, x, maxSnp, maxStep, matCorr, tofInfo, signCorr); } template GPUd() bool propagateToAlphaX(track_T& track, value_type alpha, value_type x, bool bzOnly = false, value_type maxSnp = MAX_SIN_PHI, value_type maxStep = MAX_STEP, int minSteps = 1, MatCorrType matCorr = MatCorrType::USEMatCorrLUT, track::TrackLTIntegral* tofInfo = nullptr, int signCorr = 0) const; + GPUd() bool propagateToAlphaX(TrackParCov_t& track, TrackPar_t* linRef, value_type alpha, value_type x, bool bzOnly = false, value_type maxSnp = MAX_SIN_PHI, value_type maxStep = MAX_STEP, int minSteps = 1, + MatCorrType matCorr = MatCorrType::USEMatCorrLUT, track::TrackLTIntegral* tofInfo = nullptr, int signCorr = 0) const; + + template + GPUd() bool propagateToR(track_T& track, value_type r, 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; + GPUd() bool propagateToDCA(const o2::dataformats::VertexBase& vtx, o2::track::TrackParametrizationWithError& track, value_type bZ, value_type maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrLUT, o2::dataformats::DCA* dcaInfo = nullptr, track::TrackLTIntegral* tofInfo = nullptr, @@ -111,12 +146,12 @@ class PropagatorImpl GPUd() bool propagateToDCA(const o2::math_utils::Point3D& vtx, o2::track::TrackParametrization& track, value_type bZ, value_type maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrLUT, - gpu::gpustd::array* dca = nullptr, track::TrackLTIntegral* tofInfo = nullptr, + std::array* dca = nullptr, track::TrackLTIntegral* tofInfo = nullptr, int signCorr = 0, value_type maxD = 999.f) const; GPUd() bool propagateToDCABxByBz(const o2::math_utils::Point3D& vtx, o2::track::TrackParametrization& track, value_type maxStep = MAX_STEP, MatCorrType matCorr = MatCorrType::USEMatCorrLUT, - gpu::gpustd::array* dca = nullptr, track::TrackLTIntegral* tofInfo = nullptr, + std::array* dca = nullptr, track::TrackLTIntegral* tofInfo = nullptr, int signCorr = 0, value_type maxD = 999.f) const; PropagatorImpl(PropagatorImpl const&) = delete; @@ -157,6 +192,10 @@ class PropagatorImpl GPUd() void getFieldXYZ(const math_utils::Point3D xyz, double* bxyz) const; + GPUd() float getBz(const math_utils::Point3D xyz) const; + + GPUd() double getBz(const math_utils::Point3D xyz) const; + private: #ifndef GPUCA_GPUCODE PropagatorImpl(bool uninitialized = false); @@ -165,6 +204,8 @@ class PropagatorImpl static constexpr value_type Epsilon = 0.00001; // precision of propagation to X template GPUd() void getFieldXYZImpl(const math_utils::Point3D xyz, T* bxyz) const; + template + GPUd() T getBzImpl(const math_utils::Point3D xyz) const; const o2::field::MagFieldFast* mFieldFast = nullptr; ///< External fast field map (barrel only for the moment) o2::field::MagneticField* mField = nullptr; ///< External nominal field map diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TracerGPU.h b/Detectors/Base/include/DetectorsBase/TGeoGeometryUtils.h similarity index 52% rename from Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TracerGPU.h rename to Detectors/Base/include/DetectorsBase/TGeoGeometryUtils.h index e2bd7266caff9..5ec85f1c14702 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TracerGPU.h +++ b/Detectors/Base/include/DetectorsBase/TGeoGeometryUtils.h @@ -8,31 +8,31 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// -#include "ITStracking/Definitions.h" -#ifndef TRACKINGITSGPU_INCLUDE_TRACER_H -#define TRACKINGITSGPU_INCLUDE_TRACER_H +/// \file TGeoGeometryUtils.h +/// \author Sandro Wenzel (CERN) +/// \brief Collection of utility functions for TGeo + +#ifndef ALICEO2_BASE_TGEOGEOMETRYUTILS_H_ +#define ALICEO2_BASE_TGEOGEOMETRYUTILS_H_ + +class TGeoShape; +class TGeoTessellated; -#if defined(__CUDACC__) && defined(__USE_GPU_TRACER__) namespace o2 { -namespace its +namespace base { -namespace gpu -{ -class Tracer + +/// A few utility functions to operate on TGeo geometries (transformations, printing, ...) +class TGeoGeometryUtils { public: - Tracer(const char* name, int color_id = 0); - ~Tracer(); + ///< Transform any (primitive) TGeoShape to a tessellated representation + static TGeoTessellated* TGeoShapeToTGeoTessellated(TGeoShape const*); }; -} // namespace gpu -} // namespace its + +} // namespace base } // namespace o2 -#define RANGE(name, cid) o2::its::gpu::Tracer tracer(name, cid); -#else -#define RANGE(name, cid) -#endif -#endif // TRACKINGITSGPU_INCLUDE_TRACER_H \ No newline at end of file +#endif diff --git a/Detectors/Base/src/DetectorsBaseLinkDef.h b/Detectors/Base/src/DetectorsBaseLinkDef.h index bd76e9bfbe2e4..8255c143ebb4a 100644 --- a/Detectors/Base/src/DetectorsBaseLinkDef.h +++ b/Detectors/Base/src/DetectorsBaseLinkDef.h @@ -42,4 +42,6 @@ #pragma link C++ class o2::data::Stack + ; +#pragma link C++ class o2::base::O2Tessellated - ; + #endif diff --git a/Detectors/Base/src/GeometryManager.cxx b/Detectors/Base/src/GeometryManager.cxx index c5e7e8e47e731..a067767752a69 100644 --- a/Detectors/Base/src/GeometryManager.cxx +++ b/Detectors/Base/src/GeometryManager.cxx @@ -24,6 +24,7 @@ #include #include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/GeometryManagerParam.h" #include "DetectorsCommonDataFormats/AlignParam.h" #include "CommonUtils/NameConf.h" #include "DetectorsBase/Aligner.h" @@ -256,7 +257,7 @@ bool GeometryManager::applyAlignment(const std::vector(mFlatBufferPtr + offs)); + o2::gpu::FlatObject::FlatObject::resizeArray(mPhiBin2Slice, 0, nphi, reinterpret_cast(mFlatBufferPtr + offs)); mNPhiSlices = mNPhiBins = nphi; for (int i = nphi; i--;) { @@ -92,10 +92,10 @@ void MatLayerCyl::initSegmentation(float rMin, float rMax, float zHalfSpan, int offs = alignSize(offs + nphi * sizeof(short), getBufferAlignmentBytes()); // account for alignment - o2::gpu::resizeArray(mSliceCos, 0, nphi, reinterpret_cast(mFlatBufferPtr + offs)); // in the beginning nslice = nphi + o2::gpu::FlatObject::resizeArray(mSliceCos, 0, nphi, reinterpret_cast(mFlatBufferPtr + offs)); // in the beginning nslice = nphi offs = alignSize(offs + nphi * sizeof(float), getBufferAlignmentBytes()); // account for alignment - o2::gpu::resizeArray(mSliceSin, 0, nphi, reinterpret_cast(mFlatBufferPtr + offs)); // in the beginning nslice = nphi + o2::gpu::FlatObject::resizeArray(mSliceSin, 0, nphi, reinterpret_cast(mFlatBufferPtr + offs)); // in the beginning nslice = nphi offs = alignSize(offs + nphi * sizeof(float), getBufferAlignmentBytes()); // account for alignment for (int i = nphi; i--;) { @@ -103,7 +103,7 @@ void MatLayerCyl::initSegmentation(float rMin, float rMax, float zHalfSpan, int mSliceSin[i] = o2::math_utils::sin(getPhiBinMin(i)); } - o2::gpu::resizeArray(mCells, 0, getNCells(), reinterpret_cast(mFlatBufferPtr + offs)); + o2::gpu::FlatObject::resizeArray(mCells, 0, getNCells(), reinterpret_cast(mFlatBufferPtr + offs)); mConstructionMask = InProgress; } @@ -245,10 +245,10 @@ void MatLayerCyl::optimizePhiSlices(float maxRelDiff) // mSliceCos pointer does not change, but sliceSin needs to be relocated auto offs = alignSize(newSl * sizeof(float), getBufferAlignmentBytes()); char* dst = ((char*)mSliceCos) + offs; // account for alignment - o2::gpu::resizeArray(mSliceSin, getNPhiBins(), newSl, reinterpret_cast(dst)); + o2::gpu::FlatObject::resizeArray(mSliceSin, getNPhiBins(), newSl, reinterpret_cast(dst)); // adjust mCells array dst = ((char*)mSliceSin) + offs; // account for alignment - o2::gpu::resizeArray(mCells, getNPhiBins() * getNZBins(), newSl * getNZBins(), reinterpret_cast(dst)); + o2::gpu::FlatObject::resizeArray(mCells, getNPhiBins() * getNZBins(), newSl * getNZBins(), reinterpret_cast(dst)); mFlatBufferSize = estimateFlatBufferSize(); LOG(info) << "Updated Nslices = " << getNPhiSlices(); } @@ -313,15 +313,30 @@ void MatLayerCyl::flatten(char* newPtr) // make object flat: move all content to single internally allocated buffer assert(mConstructionMask == InProgress); fixPointers(mFlatBufferPtr, newPtr); - auto old = o2::gpu::resizeArray(mFlatBufferPtr, getFlatBufferSize(), getFlatBufferSize(), newPtr); + auto old = o2::gpu::FlatObject::resizeArray(mFlatBufferPtr, getFlatBufferSize(), getFlatBufferSize(), newPtr); delete[] old; mFlatBufferContainer = nullptr; mConstructionMask = Constructed; } +//________________________________________________________________________________ +void MatLayerCyl::scale(float factor, bool _x2x0, bool _rho) +{ + LOGP(info, "Scaling layer {:.3f}mLayers, nlr, nlr + 1); + auto* oldLayers = o2::gpu::FlatObject::resizeArray(get()->mLayers, nlr, nlr + 1); // dynamyc buffers of old layers were used in new ones, detach them for (int i = nlr; i--;) { oldLayers[i].clearInternalBufferPtr(); @@ -98,8 +98,8 @@ void MatLayerCylSet::finalizeStructures() assert(mConstructionMask == InProgress); int nlr = getNLayers(); int nR2Int = 2 * (nlr + 1); - o2::gpu::resizeArray(get()->mR2Intervals, 0, nR2Int); - o2::gpu::resizeArray(get()->mInterval2LrID, 0, nR2Int); + o2::gpu::FlatObject::resizeArray(get()->mR2Intervals, 0, nR2Int); + o2::gpu::FlatObject::resizeArray(get()->mInterval2LrID, 0, nR2Int); get()->mR2Intervals[0] = get()->mRMin2; get()->mR2Intervals[1] = get()->mRMax2; get()->mInterval2LrID[0] = 0; @@ -116,8 +116,8 @@ void MatLayerCylSet::finalizeStructures() get()->mInterval2LrID[nRIntervals] = i; get()->mR2Intervals[++nRIntervals] = lr.getRMax2(); } - delete[] o2::gpu::resizeArray(get()->mInterval2LrID, nR2Int, nRIntervals); // rebook with precise size - delete[] o2::gpu::resizeArray(get()->mR2Intervals, nR2Int, ++nRIntervals); // rebook with precise size + delete[] o2::gpu::FlatObject::resizeArray(get()->mInterval2LrID, nR2Int, nRIntervals); // rebook with precise size + delete[] o2::gpu::FlatObject::resizeArray(get()->mR2Intervals, nR2Int, ++nRIntervals); // rebook with precise size // } @@ -256,6 +256,33 @@ void MatLayerCylSet::print(bool data) const float(getFlatBufferSize()) / 1024 / 1024); } +//________________________________________________________________________________ +void MatLayerCylSet::scaleLayersByID(int lrFrom, int lrTo, float factor, bool _x2x0, bool _rho) +{ + lrFrom = std::max(0, std::min(lrFrom, get()->mNLayers - 1)); + lrTo = std::max(0, std::min(lrTo, get()->mNLayers - 1)); + int dir = lrFrom >= lrTo ? -1 : 1; + lrTo += dir; + for (int i = lrFrom; i != lrTo; i += dir) { + get()->mLayers[i].scale(factor, _x2x0, _rho); + } +} + +//________________________________________________________________________________ +void MatLayerCylSet::scaleLayersByR(float rFrom, float rTo, float factor, bool _x2x0, bool _rho) +{ + if (rFrom > rTo) { + std::swap(rFrom, rTo); + } + Ray ray(std::max(getRMin(), rFrom), 0., 0., std::min(getRMax(), rTo), 0., 0.); + short lmin, lmax; + if (!getLayersRange(ray, lmin, lmax)) { + LOGP(warn, "No layers found for {} < r < {}", rFrom, rTo); + return; + } + scaleLayersByID(lmin, lmax, factor, _x2x0, _rho); +} + #endif //!GPUCA_ALIGPUCODE #ifndef GPUCA_GPUCODE @@ -481,14 +508,14 @@ void MatLayerCylSet::flatten() int sz = estimateFlatBufferSize(); // create new internal buffer with total size and copy data - delete[] o2::gpu::resizeArray(mFlatBufferContainer, mFlatBufferSize, sz); + delete[] o2::gpu::FlatObject::resizeArray(mFlatBufferContainer, mFlatBufferSize, sz); mFlatBufferPtr = mFlatBufferContainer; mFlatBufferSize = sz; int nLr = getNLayers(); auto offs = alignSize(sizeof(MatLayerCylSetLayout), getBufferAlignmentBytes()); // account for the alignment // move array of layer pointers to the flat array - auto* oldLayers = o2::gpu::resizeArray(get()->mLayers, nLr, nLr, (MatLayerCyl*)(mFlatBufferPtr + offs)); + auto* oldLayers = o2::gpu::FlatObject::resizeArray(get()->mLayers, nLr, nLr, (MatLayerCyl*)(mFlatBufferPtr + offs)); // dynamyc buffers of old layers were used in new ones, detach them for (int i = nLr; i--;) { oldLayers[i].clearInternalBufferPtr(); @@ -497,11 +524,11 @@ void MatLayerCylSet::flatten() offs = alignSize(offs + nLr * sizeof(MatLayerCyl), MatLayerCyl::getClassAlignmentBytes()); // account for the alignment // move array of R2 boundaries to the flat array - delete[] o2::gpu::resizeArray(get()->mR2Intervals, nLr + 1, nLr + 1, (float*)(mFlatBufferPtr + offs)); + delete[] o2::gpu::FlatObject::resizeArray(get()->mR2Intervals, nLr + 1, nLr + 1, (float*)(mFlatBufferPtr + offs)); offs = alignSize(offs + (nLr + 1) * sizeof(float), getBufferAlignmentBytes()); // account for the alignment // move array of R2 boundaries to the flat array - delete[] o2::gpu::resizeArray(get()->mInterval2LrID, nLr, nLr, (int*)(mFlatBufferPtr + offs)); + delete[] o2::gpu::FlatObject::resizeArray(get()->mInterval2LrID, nLr, nLr, (int*)(mFlatBufferPtr + offs)); offs = alignSize(offs + nLr * sizeof(int), getBufferAlignmentBytes()); // account for the alignment for (int il = 0; il < nLr; il++) { @@ -581,8 +608,12 @@ void MatLayerCylSet::fixPointers(char* oldPtr, char* newPtr, bool newPtrValid) #ifndef GPUCA_ALIGPUCODE // this part is unvisible on GPU version -MatLayerCylSet* MatLayerCylSet::extractCopy(float rmin, float rmax, float tolerance) const +MatLayerCylSet* MatLayerCylSet::extractCopy(float rmin, float rmax, float tolerance, const MatLayerCylSet* addTo) const { + // extract layers in the covering rmin-rmax range. If addTo is provided, simply substitute its layers by those from this + if (addTo && addTo->getNLayers() != getNLayers()) { + LOGP(fatal, "addTo has {} layers, this has {}", addTo->getNLayers(), getNLayers()); + } Ray ray(std::max(getRMin(), rmin), 0., 0., std::min(getRMax(), rmax), 0., 0.); short lmin, lmax; if (!getLayersRange(ray, lmin, lmax)) { @@ -591,23 +622,37 @@ MatLayerCylSet* MatLayerCylSet::extractCopy(float rmin, float rmax, float tolera } LOGP(info, "Will extract layers {}:{} (out of {} layers) for {} < r < {}", lmin, lmax, getNLayers(), rmin, rmax); MatLayerCylSet* copy = new MatLayerCylSet(); - int lrCount = 0; - for (int il = lmin; il <= lmax; il++) { - const auto& lr = getLayer(il); + int lrCount = 0, lrCounOld = 0, lrCountTot = 0; + auto addLr = [copy, &lrCountTot](const MatLayerCyl& lr) { float drphi = lr.getDPhi() * (lr.getRMin() + lr.getRMax()) / 2. * 0.999; copy->addLayer(lr.getRMin(), lr.getRMax(), lr.getZMax(), lr.getDZ(), drphi); - auto& lrNew = copy->getLayer(lrCount); + auto& lrNew = copy->getLayer(lrCountTot++); for (int iz = 0; iz < lrNew.getNZBins(); iz++) { for (int ip = 0; ip < lrNew.getNPhiBins(); ip++) { lrNew.getCellPhiBin(ip, iz).set(lr.getCellPhiBin(ip, iz)); } } + }; + if (addTo) { + for (int il = 0; il < lmin; il++) { + addLr(addTo->getLayer(il)); + lrCounOld++; + } + } + for (int il = lmin; il <= lmax; il++) { + addLr(getLayer(il)); lrCount++; } - + if (addTo) { + for (int il = lmax + 1; il < getNLayers(); il++) { + addLr(addTo->getLayer(il)); + lrCounOld++; + } + } copy->finalizeStructures(); copy->optimizePhiSlices(tolerance); copy->flatten(); + LOGP(info, "Added layers {}:{} for {}second << " from material match"; + } + return iter->second; } - return o2::conf::SimMaterialParams::Instance().globalDensityFactor; + // density on module level + iter = mDensityMap.find(modname); + if (iter != mDensityMap.end()) { + if (debug) { + LOG(info) << "MatManager - " << modname << "/" << matname << " : applying density " << iter->second << " from module match"; + } + return iter->second; + } + // global factor + const auto global = o2::conf::SimMaterialParams::Instance().globalDensityFactor; + if (debug && global != 1.0) { + LOG(info) << "MatManager - " << modname << "/" << matname << " : applying global density " << iter->second; + } + return global; } void MaterialManager::Material(const char* modname, Int_t imat, const char* name, Float_t a, Float_t z, Float_t dens, Float_t radl, Float_t absl, Float_t* buf, Int_t nwbuf) { TString uniquename = modname; - auto densityFactor = getDensity(modname); + auto densityFactor = getDensity(modname, name); + uniquename.Append("_"); uniquename.Append(name); if (TVirtualMC::GetMC()) { @@ -173,7 +202,7 @@ void MaterialManager::Mixture(const char* modname, Int_t imat, const char* name, Int_t nlmat, Float_t* wmat) { TString uniquename = modname; - auto densityFactor = getDensity(modname); + auto densityFactor = getDensity(modname, name); uniquename.Append("_"); uniquename.Append(name); diff --git a/Detectors/Base/src/O2Tessellated.cxx b/Detectors/Base/src/O2Tessellated.cxx new file mode 100644 index 0000000000000..256a70e5a697a --- /dev/null +++ b/Detectors/Base/src/O2Tessellated.cxx @@ -0,0 +1,1509 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// Sandro Wenzel 2026 + +// An implementation of TGeoTessellated augmented with efficient navigation functions. +// Asked for integration into ROOT here https://github.com/root-project/root/pull/21045 +// Will be deleted once we get this from ROOT. + +#include +#include + +#include "TGeoManager.h" +#include "TGeoMatrix.h" +#include "TGeoVolume.h" +#include "TVirtualGeoPainter.h" +#include "DetectorsBase/O2Tessellated.h" +#include "TBuffer3D.h" +#include "TBuffer3DTypes.h" +#include "TMath.h" +#include "TBuffer.h" + +#include +#include + +// THIS IS THIRD PARTY CODE (TO BE PUT IN ROOT) WHICH DOES NOT NEED TO ADHERE TO OUR LINTING +// NOLINTBEGIN + +// include the Third-party BVH headers +#include "bvh2_third_party.h" +// some kernels on top of BVH +#include "bvh2_extra_kernels.h" + +#include +#include + +using namespace o2::base; +ClassImp(O2Tessellated); + +using Vertex_t = Tessellated::Vertex_t; + +//////////////////////////////////////////////////////////////////////////////// +/// Compact consecutive equal vertices + +int TGeoFacet::CompactFacet(Vertex_t* vert, int nvertices) +{ + // Compact the common vertices and return new facet + if (nvertices < 2) + return nvertices; + int nvert = nvertices; + int i = 0; + while (i < nvert) { + if (vert[(i + 1) % nvert] == vert[i]) { + // shift last vertices left by one element + for (int j = i + 2; j < nvert; ++j) + vert[j - 1] = vert[j]; + nvert--; + } + i++; + } + return nvert; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Check if a connected neighbour facet has compatible normal + +bool TGeoFacet::IsNeighbour(const TGeoFacet& other, bool& flip) const +{ + + // Find a connecting segment + bool neighbour = false; + int line1[2], line2[2]; + int npoints = 0; + for (int i = 0; i < fNvert; ++i) { + auto ivert = fIvert[i]; + // Check if the other facet has the same vertex + for (int j = 0; j < other.GetNvert(); ++j) { + if (ivert == other[j]) { + line1[npoints] = i; + line2[npoints] = j; + if (++npoints == 2) { + neighbour = true; + bool order1 = line1[1] == line1[0] + 1; + bool order2 = line2[1] == (line2[0] + 1) % other.GetNvert(); + flip = (order1 == order2); + return neighbour; + } + } + } + } + return neighbour; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Constructor. In case nfacets is zero, it is user's responsibility to +/// call CloseShape once all faces are defined. + +O2Tessellated::O2Tessellated(const char* name, int nfacets) : TGeoBBox(name, 0, 0, 0) +{ + fNfacets = nfacets; + if (nfacets) + fFacets.reserve(nfacets); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Constructor providing directly the array of vertices. Facets have to be added +/// providing vertex indices rather than coordinates. + +O2Tessellated::O2Tessellated(const char* name, const std::vector& vertices) : TGeoBBox(name, 0, 0, 0) +{ + fVertices = vertices; + fNvert = fVertices.size(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Construct from TGeoTessellated + +O2Tessellated::O2Tessellated(TGeoTessellated const& tsl, bool check) : TGeoBBox(tsl.GetName(), 0, 0, 0) +{ + fNfacets = tsl.GetNfacets(); + fNvert = tsl.GetNvertices(); + fNseg = tsl.GetNsegments(); + + // copy facet and vertex done + fVertices.reserve(fNvert); + fFacets.reserve(fNfacets); + for (int i = 0; i < fNfacets; ++i) { + fFacets.push_back(tsl.GetFacet(i)); + } + for (int i = 0; i < fNvert; ++i) { + fVertices.push_back(tsl.GetVertex(i)); + } + // finish remaining structures + CloseShape(check); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Add a vertex checking for duplicates, returning the vertex index + +int O2Tessellated::AddVertex(Vertex_t const& vert) +{ + constexpr double tolerance = 1.e-10; + auto vertexHash = [&](Vertex_t const& vertex) { + // Compute hash for the vertex + long hash = 0; + // helper function to generate hash from integer numbers + auto hash_combine = [](long seed, const long value) { + return seed ^ (std::hash{}(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2)); + }; + for (int i = 0; i < 3; i++) { + // use tolerance to generate int with the desired precision from a real number for hashing + hash = hash_combine(hash, std::roundl(vertex[i] / tolerance)); + } + return hash; + }; + + auto hash = vertexHash(vert); + bool isAdded = false; + int ivert = -1; + // Get the compatible vertices + auto range = fVerticesMap.equal_range(hash); + for (auto it = range.first; it != range.second; ++it) { + ivert = it->second; + if (fVertices[ivert] == vert) { + isAdded = true; + break; + } + } + if (!isAdded) { + ivert = fVertices.size(); + fVertices.push_back(vert); + fVerticesMap.insert(std::make_pair(hash, ivert)); + } + return ivert; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Adding a triangular facet from vertex positions in absolute coordinates + +bool O2Tessellated::AddFacet(const Vertex_t& pt0, const Vertex_t& pt1, const Vertex_t& pt2) +{ + if (fDefined) { + Error("AddFacet", "Shape %s already fully defined. Not adding", GetName()); + return false; + } + + Vertex_t vert[3]; + vert[0] = pt0; + vert[1] = pt1; + vert[2] = pt2; + int nvert = TGeoFacet::CompactFacet(vert, 3); + if (nvert < 3) { + Error("AddFacet", "Triangular facet at index %d degenerated. Not adding.", GetNfacets()); + return false; + } + int ind[3]; + for (auto i = 0; i < 3; ++i) + ind[i] = AddVertex(vert[i]); + fNseg += 3; + fFacets.emplace_back(ind[0], ind[1], ind[2]); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Adding a triangular facet from indices of vertices + +bool O2Tessellated::AddFacet(int i0, int i1, int i2) +{ + if (fDefined) { + Error("AddFacet", "Shape %s already fully defined. Not adding", GetName()); + return false; + } + if (fVertices.empty()) { + Error("AddFacet", "Shape %s Cannot add facets by indices without vertices. Not adding", GetName()); + return false; + } + + fNseg += 3; + fFacets.emplace_back(i0, i1, i2); + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Adding a quadrilateral facet from vertex positions in absolute coordinates + +bool O2Tessellated::AddFacet(const Vertex_t& pt0, const Vertex_t& pt1, const Vertex_t& pt2, const Vertex_t& pt3) +{ + if (fDefined) { + Error("AddFacet", "Shape %s already fully defined. Not adding", GetName()); + return false; + } + Vertex_t vert[4]; + vert[0] = pt0; + vert[1] = pt1; + vert[2] = pt2; + vert[3] = pt3; + int nvert = TGeoFacet::CompactFacet(vert, 4); + if (nvert < 3) { + Error("AddFacet", "Quadrilateral facet at index %d degenerated. Not adding.", GetNfacets()); + return false; + } + + int ind[4]; + for (auto i = 0; i < nvert; ++i) + ind[i] = AddVertex(vert[i]); + fNseg += nvert; + if (nvert == 3) + fFacets.emplace_back(ind[0], ind[1], ind[2]); + else + fFacets.emplace_back(ind[0], ind[1], ind[2], ind[3]); + + if (fNfacets > 0 && GetNfacets() == fNfacets) + CloseShape(false); + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Adding a quadrilateral facet from indices of vertices + +bool O2Tessellated::AddFacet(int i0, int i1, int i2, int i3) +{ + if (fDefined) { + Error("AddFacet", "Shape %s already fully defined. Not adding", GetName()); + return false; + } + if (fVertices.empty()) { + Error("AddFacet", "Shape %s Cannot add facets by indices without vertices. Not adding", GetName()); + return false; + } + + fNseg += 4; + fFacets.emplace_back(i0, i1, i2, i3); + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Compute normal for a given facet + +Vertex_t O2Tessellated::FacetComputeNormal(int ifacet, bool& degenerated) const +{ + // Compute normal using non-zero segments + constexpr double kTolerance = 1.e-20; + auto const& facet = fFacets[ifacet]; + int nvert = facet.GetNvert(); + degenerated = true; + Vertex_t normal; + for (int i = 0; i < nvert - 1; ++i) { + Vertex_t e1 = fVertices[facet[i + 1]] - fVertices[facet[i]]; + if (e1.Mag2() < kTolerance) + continue; + for (int j = i + 1; j < nvert; ++j) { + Vertex_t e2 = fVertices[facet[(j + 1) % nvert]] - fVertices[facet[j]]; + if (e2.Mag2() < kTolerance) + continue; + normal = Vertex_t::Cross(e1, e2); + // e1 and e2 may be colinear + if (normal.Mag2() < kTolerance) + continue; + normal.Normalize(); + degenerated = false; + break; + } + if (!degenerated) + break; + } + return normal; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Check validity of facet + +bool O2Tessellated::FacetCheck(int ifacet) const +{ + constexpr double kTolerance = 1.e-10; + auto const& facet = fFacets[ifacet]; + int nvert = facet.GetNvert(); + bool degenerated = true; + FacetComputeNormal(ifacet, degenerated); + if (degenerated) { + std::cout << "Facet: " << ifacet << " is degenerated\n"; + return false; + } + + // Compute surface area + double surfaceArea = 0.; + for (int i = 1; i < nvert - 1; ++i) { + Vertex_t e1 = fVertices[facet[i]] - fVertices[facet[0]]; + Vertex_t e2 = fVertices[facet[i + 1]] - fVertices[facet[0]]; + surfaceArea += 0.5 * Vertex_t::Cross(e1, e2).Mag(); + } + if (surfaceArea < kTolerance) { + std::cout << "Facet: " << ifacet << " has zero surface area\n"; + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Close the shape: calculate bounding box and compact vertices + +void O2Tessellated::CloseShape(bool check, bool fixFlipped, bool verbose) +{ + if (fIsClosed && fBVH) { + return; + } + // Compute bounding box + fDefined = true; + fNvert = fVertices.size(); + fNfacets = fFacets.size(); + ComputeBBox(); + + BuildBVH(); + if (fOutwardNormals.size() == 0) { + CalculateNormals(); + } else { + // short check if the normal container is of correct size + if (fOutwardNormals.size() != fFacets.size()) { + std::cerr << "Inconsistency in normal container"; + } + } + fIsClosed = true; + + // Cleanup the vertex map + std::multimap().swap(fVerticesMap); + + if (fVertices.size() > 0) { + if (!check) + return; + + // Check facets + for (auto i = 0; i < fNfacets; ++i) + FacetCheck(i); + + fClosedBody = CheckClosure(fixFlipped, verbose); + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Check closure of the solid and check/fix flipped normals + +bool O2Tessellated::CheckClosure(bool fixFlipped, bool verbose) +{ + int* nn = new int[fNfacets]; + bool* flipped = new bool[fNfacets]; + bool hasorphans = false; + bool hasflipped = false; + for (int i = 0; i < fNfacets; ++i) { + nn[i] = 0; + flipped[i] = false; + } + + for (int icrt = 0; icrt < fNfacets; ++icrt) { + // all neighbours checked? + if (nn[icrt] >= fFacets[icrt].GetNvert()) + continue; + for (int i = icrt + 1; i < fNfacets; ++i) { + bool isneighbour = fFacets[icrt].IsNeighbour(fFacets[i], flipped[i]); + if (isneighbour) { + if (flipped[icrt]) + flipped[i] = !flipped[i]; + if (flipped[i]) + hasflipped = true; + nn[icrt]++; + nn[i]++; + if (nn[icrt] == fFacets[icrt].GetNvert()) + break; + } + } + if (nn[icrt] < fFacets[icrt].GetNvert()) + hasorphans = true; + } + + if (hasorphans && verbose) { + Error("Check", "Tessellated solid %s has following not fully connected facets:", GetName()); + for (int icrt = 0; icrt < fNfacets; ++icrt) { + if (nn[icrt] < fFacets[icrt].GetNvert()) + std::cout << icrt << " (" << fFacets[icrt].GetNvert() << " edges, " << nn[icrt] << " neighbours)\n"; + } + } + fClosedBody = !hasorphans; + int nfixed = 0; + if (hasflipped) { + if (verbose) + Warning("Check", "Tessellated solid %s has following facets with flipped normals:", GetName()); + for (int icrt = 0; icrt < fNfacets; ++icrt) { + if (flipped[icrt]) { + if (verbose) + std::cout << icrt << "\n"; + if (fixFlipped) { + fFacets[icrt].Flip(); + nfixed++; + } + } + } + if (nfixed && verbose) + Info("Check", "Automatically flipped %d facets to match first defined facet", nfixed); + } + delete[] nn; + delete[] flipped; + + return !hasorphans; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Compute bounding box + +void O2Tessellated::ComputeBBox() +{ + const double kBig = TGeoShape::Big(); + double vmin[3] = {kBig, kBig, kBig}; + double vmax[3] = {-kBig, -kBig, -kBig}; + for (const auto& facet : fFacets) { + for (int i = 0; i < facet.GetNvert(); ++i) { + for (int j = 0; j < 3; ++j) { + vmin[j] = TMath::Min(vmin[j], fVertices[facet[i]].operator[](j)); + vmax[j] = TMath::Max(vmax[j], fVertices[facet[i]].operator[](j)); + } + } + } + fDX = 0.5 * (vmax[0] - vmin[0]); + fDY = 0.5 * (vmax[1] - vmin[1]); + fDZ = 0.5 * (vmax[2] - vmin[2]); + for (int i = 0; i < 3; ++i) + fOrigin[i] = 0.5 * (vmax[i] + vmin[i]); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Returns numbers of vertices, segments and polygons composing the shape mesh. + +void O2Tessellated::GetMeshNumbers(int& nvert, int& nsegs, int& npols) const +{ + nvert = fNvert; + nsegs = fNseg; + npols = GetNfacets(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Creates a TBuffer3D describing *this* shape. +/// Coordinates are in local reference frame. + +TBuffer3D* O2Tessellated::MakeBuffer3D() const +{ + const int nvert = fNvert; + const int nsegs = fNseg; + const int npols = GetNfacets(); + auto buff = new TBuffer3D(TBuffer3DTypes::kGeneric, nvert, 3 * nvert, nsegs, 3 * nsegs, npols, 6 * npols); + if (buff) { + SetPoints(buff->fPnts); + SetSegsAndPols(*buff); + } + return buff; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Prints basic info + +void O2Tessellated::Print(Option_t*) const +{ + std::cout << "=== Tessellated shape " << GetName() << " having " << GetNvertices() << " vertices and " + << GetNfacets() << " facets\n"; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Fills TBuffer3D structure for segments and polygons. + +void O2Tessellated::SetSegsAndPols(TBuffer3D& buff) const +{ + const int c = GetBasicColor(); + int* segs = buff.fSegs; + int* pols = buff.fPols; + + int indseg = 0; // segment internal data index + int indpol = 0; // polygon internal data index + int sind = 0; // segment index + for (const auto& facet : fFacets) { + auto nvert = facet.GetNvert(); + pols[indpol++] = c; + pols[indpol++] = nvert; + for (auto j = 0; j < nvert; ++j) { + int k = (j + 1) % nvert; + // segment made by next consecutive points + segs[indseg++] = c; + segs[indseg++] = facet[j]; + segs[indseg++] = facet[k]; + // add segment to current polygon and increment segment index + pols[indpol + nvert - j - 1] = sind++; + } + indpol += nvert; + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Fill tessellated points to an array. + +void O2Tessellated::SetPoints(double* points) const +{ + int ind = 0; + for (const auto& vertex : fVertices) { + vertex.CopyTo(&points[ind]); + ind += 3; + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Fill tessellated points in float. + +void O2Tessellated::SetPoints(Float_t* points) const +{ + int ind = 0; + for (const auto& vertex : fVertices) { + points[ind++] = vertex.x(); + points[ind++] = vertex.y(); + points[ind++] = vertex.z(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Resize the shape by scaling vertices within maxsize and center to origin + +void O2Tessellated::ResizeCenter(double maxsize) +{ + using Vector3_t = Vertex_t; + + if (!fDefined) { + Error("ResizeCenter", "Not all faces are defined"); + return; + } + Vector3_t origin(fOrigin[0], fOrigin[1], fOrigin[2]); + double maxedge = TMath::Max(TMath::Max(fDX, fDY), fDZ); + double scale = maxsize / maxedge; + for (size_t i = 0; i < fVertices.size(); ++i) { + fVertices[i] = scale * (fVertices[i] - origin); + } + fOrigin[0] = fOrigin[1] = fOrigin[2] = 0; + fDX *= scale; + fDY *= scale; + fDZ *= scale; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Fills a static 3D buffer and returns a reference. + +const TBuffer3D& O2Tessellated::GetBuffer3D(int reqSections, Bool_t localFrame) const +{ + static TBuffer3D buffer(TBuffer3DTypes::kGeneric); + + FillBuffer3D(buffer, reqSections, localFrame); + + const int nvert = fNvert; + const int nsegs = fNseg; + const int npols = GetNfacets(); + + if (reqSections & TBuffer3D::kRawSizes) { + if (buffer.SetRawSizes(nvert, 3 * nvert, nsegs, 3 * nsegs, npols, 6 * npols)) { + buffer.SetSectionsValid(TBuffer3D::kRawSizes); + } + } + if ((reqSections & TBuffer3D::kRaw) && buffer.SectionsValid(TBuffer3D::kRawSizes)) { + SetPoints(buffer.fPnts); + if (!buffer.fLocalFrame) { + TransformPoints(buffer.fPnts, buffer.NbPnts()); + } + + SetSegsAndPols(buffer); + buffer.SetSectionsValid(TBuffer3D::kRaw); + } + + return buffer; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Reads a single tessellated solid from an .obj file. + +O2Tessellated* O2Tessellated::ImportFromObjFormat(const char* objfile, bool check, bool verbose) +{ + using std::vector, std::string, std::ifstream, std::stringstream, std::endl; + + vector vertices; + vector sfacets; + + struct FacetInd_t { + int i0 = -1; + int i1 = -1; + int i2 = -1; + int i3 = -1; + int nvert = 0; + FacetInd_t(int a, int b, int c) + { + i0 = a; + i1 = b; + i2 = c; + nvert = 3; + }; + FacetInd_t(int a, int b, int c, int d) + { + i0 = a; + i1 = b; + i2 = c; + i3 = d; + nvert = 4; + }; + }; + + vector facets; + // List of geometric vertices, with (x, y, z [,w]) coordinates, w is optional and defaults to 1.0. + // struct vtx_t { double x = 0; double y = 0; double z = 0; double w = 1; }; + + // Texture coordinates in u, [,v ,w]) coordinates, these will vary between 0 and 1. v, w are optional and default to + // 0. + // struct tex_t { double u; double v; double w; }; + + // List of vertex normals in (x,y,z) form; normals might not be unit vectors. + // struct vn_t { double x; double y; double z; }; + + // Parameter space vertices in ( u [,v] [,w] ) form; free form geometry statement + // struct vp_t { double u; double v; double w; }; + + // Faces are defined using lists of vertex, texture and normal indices which start at 1. + // Polygons such as quadrilaterals can be defined by using more than three vertex/texture/normal indices. + // f v1//vn1 v2//vn2 v3//vn3 ... + + // Records starting with the letter "l" specify the order of the vertices which build a polyline. + // l v1 v2 v3 v4 v5 v6 ... + + string line; + int ind[4] = {0}; + ifstream file(objfile); + if (!file.is_open()) { + ::Error("O2Tessellated::ImportFromObjFormat", "Unable to open %s", objfile); + return nullptr; + } + + while (getline(file, line)) { + stringstream ss(line); + string tag; + + // We ignore everything which is not a vertex or a face + if (line.rfind('v', 0) == 0 && line.rfind("vt", 0) != 0 && line.rfind("vn", 0) != 0 && line.rfind("vn", 0) != 0) { + // Decode the vertex + double pos[4] = {0, 0, 0, 1}; + ss >> tag >> pos[0] >> pos[1] >> pos[2] >> pos[3]; + vertices.emplace_back(pos[0] * pos[3], pos[1] * pos[3], pos[2] * pos[3]); + } + + else if (line.rfind('f', 0) == 0) { + // Decode the face + ss >> tag; + string word; + sfacets.clear(); + while (ss >> word) + sfacets.push_back(word); + if (sfacets.size() > 4 || sfacets.size() < 3) { + ::Error("O2Tessellated::ImportFromObjFormat", "Detected face having unsupported %zu vertices", + sfacets.size()); + return nullptr; + } + int nvert = 0; + for (auto& sword : sfacets) { + stringstream ssword(sword); + string token; + getline(ssword, token, '/'); // just need the vertex index, which is the first token + // Convert string token to integer + + ind[nvert++] = stoi(token) - 1; + if (ind[nvert - 1] < 0) { + ::Error("O2Tessellated::ImportFromObjFormat", "Unsupported relative vertex index definition in %s", + objfile); + return nullptr; + } + } + if (nvert == 3) + facets.emplace_back(ind[0], ind[1], ind[2]); + else + facets.emplace_back(ind[0], ind[1], ind[2], ind[3]); + } + } + + int nvertices = (int)vertices.size(); + int nfacets = (int)facets.size(); + if (nfacets < 3) { + ::Error("O2Tessellated::ImportFromObjFormat", "Not enough faces detected in %s", objfile); + return nullptr; + } + + string sobjfile(objfile); + if (verbose) + std::cout << "Read " << nvertices << " vertices and " << nfacets << " facets from " << sobjfile << endl; + + auto tsl = new O2Tessellated(sobjfile.erase(sobjfile.find_last_of('.')).c_str(), vertices); + + for (int i = 0; i < nfacets; ++i) { + auto facet = facets[i]; + if (facet.nvert == 3) + tsl->AddFacet(facet.i0, facet.i1, facet.i2); + else + tsl->AddFacet(facet.i0, facet.i1, facet.i2, facet.i3); + } + tsl->CloseShape(check, true, verbose); + tsl->Print(); + return tsl; +} + +// implementation of some geometry helper functions in anonymous namespace +namespace +{ + +using Vertex_t = Tessellated::Vertex_t; +// The classic Moeller-Trumbore ray triangle-intersection kernel: +// - Compute triangle edges e1, e2 +// - Compute determinant det +// - Reject parallel rays +// - Compute barycentric coordinates u, v +// - Compute ray parameter t +double rayTriangle(const Vertex_t& orig, const Vertex_t& dir, const Vertex_t& v0, const Vertex_t& v1, + const Vertex_t& v2, double rayEPS = 1e-8) +{ + constexpr double EPS = 1e-8; + const double INF = std::numeric_limits::infinity(); + Vertex_t e1{v1[0] - v0[0], v1[1] - v0[1], v1[2] - v0[2]}; + Vertex_t e2{v2[0] - v0[0], v2[1] - v0[1], v2[2] - v0[2]}; + auto p = Vertex_t::Cross(dir, e2); + auto det = e1.Dot(p); + if (std::abs(det) <= EPS) { + return INF; + } + + Vertex_t tvec{orig[0] - v0[0], orig[1] - v0[1], orig[2] - v0[2]}; + auto invDet = 1.0 / det; + auto u = tvec.Dot(p) * invDet; + if (u < 0.0 || u > 1.0) { + return INF; + } + auto q = Vertex_t::Cross(tvec, e1); + auto v = dir.Dot(q) * invDet; + if (v < 0.0 || u + v > 1.0) { + return INF; + } + auto t = e2.Dot(q) * invDet; + return (t > rayEPS) ? t : INF; +} + +template +struct Vec3f { + T x, y, z; +}; + +template +inline Vec3f operator-(const Vec3f& a, const Vec3f& b) +{ + return {a.x - b.x, a.y - b.y, a.z - b.z}; +} + +template +inline Vec3f cross(const Vec3f& a, const Vec3f& b) +{ + return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x}; +} + +template +inline T dot(const Vec3f& a, const Vec3f& b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z; +} + +// Kernel to get closest/shortest distance between a point and a triangl (a,b,c). +// Performed by default in float since Safety can be approximate. +// Project point onto triangle plane +// If projection lies inside → distance to plane +// Otherwise compute min distance to the three edges +// Return squared distance +template +T pointTriangleDistSq(const Vec3f& p, const Vec3f& a, const Vec3f& b, const Vec3f& c) +{ + // Edges + Vec3f ab = b - a; + Vec3f ac = c - a; + Vec3f ap = p - a; + + auto d1 = dot(ab, ap); + auto d2 = dot(ac, ap); + if (d1 <= T(0.0) && d2 <= T(0.0)) { + return dot(ap, ap); // barycentric (1,0,0) + } + + Vec3f bp = p - b; + auto d3 = dot(ab, bp); + auto d4 = dot(ac, bp); + if (d3 >= T(0.0) && d4 <= d3) { + return dot(bp, bp); // (0,1,0) + } + + T vc = d1 * d4 - d3 * d2; + if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f) { + T v = d1 / (d1 - d3); + Vec3f proj = {a.x + v * ab.x, a.y + v * ab.y, a.z + v * ab.z}; + Vec3f d = p - proj; + return dot(d, d); // edge AB + } + + Vec3f cp = p - c; + T d5 = dot(ab, cp); + T d6 = dot(ac, cp); + if (d6 >= T(0.0f) && d5 <= d6) { + return dot(cp, cp); // (0,0,1) + } + + T vb = d5 * d2 - d1 * d6; + if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f) { + T w = d2 / (d2 - d6); + Vec3f proj = {a.x + w * ac.x, a.y + w * ac.y, a.z + w * ac.z}; + Vec3f d = p - proj; + return dot(d, d); // edge AC + } + + T va = d3 * d6 - d5 * d4; + if (va <= 0.0f && (d4 - d3) >= 0.0f && (d5 - d6) >= 0.0f) { + T w = (d4 - d3) / ((d4 - d3) + (d5 - d6)); + Vec3f proj = {b.x + w * (c.x - b.x), b.y + w * (c.y - b.y), b.z + w * (c.z - b.z)}; + Vec3f d = p - proj; + return dot(d, d); // edge BC + } + + // Inside face region + T denom = T(1.0f) / (va + vb + vc); + T v = vb * denom; + T w = vc * denom; + + Vec3f proj = {a.x + ab.x * v + ac.x * w, a.y + ab.y * v + ac.y * w, a.z + ab.z * v + ac.z * w}; + + Vec3f d = p - proj; + return dot(d, d); +} + +template +inline Vec3f normalize(const Vec3f& v) +{ + T len2 = dot(v, v); + if (len2 == T(0.0f)) { + std::cerr << "Degnerate triangle. Cannot determine normal"; + return {0, 0, 0}; + } + T invLen = T(1.0f) / std::sqrt(len2); + return {v.x * invLen, v.y * invLen, v.z * invLen}; +} + +template +inline Vec3f triangleNormal(const Vec3f& a, const Vec3f& b, const Vec3f& c) +{ + const Vec3f e1 = b - a; + const Vec3f e2 = c - a; + return normalize(cross(e1, e2)); +} + +} // end anonymous namespace + +//////////////////////////////////////////////////////////////////////////////// +/// DistFromOutside + +Double_t O2Tessellated::DistFromOutside(const Double_t* point, const Double_t* dir, Int_t /*iact*/, Double_t stepmax, + Double_t* /*safe*/) const +{ + // use the BVH intersector in combination with leaf ray-triangle testing + double local_step = Big(); // we need this otherwise the lambda get's confused + + using Scalar = float; + using Vec3 = bvh::v2::Vec; + using Node = bvh::v2::Node; + using Bvh = bvh::v2::Bvh; + using Ray = bvh::v2::Ray; + + // let's fetch the bvh + auto mybvh = (Bvh*)fBVH; + if (!mybvh) { + assert(false); + return -1.; + } + + auto truncate_roundup = [](double orig) { + float epsilon = std::numeric_limits::epsilon() * std::fabs(orig); + // Add the bias to x before assigning it to y + return static_cast(orig + epsilon); + }; + + // let's do very quick checks against the top node + const auto topnode_bbox = mybvh->get_root().get_bbox(); + if ((-point[0] + topnode_bbox.min[0]) > stepmax) { + return Big(); + } + if ((-point[1] + topnode_bbox.min[1]) > stepmax) { + return Big(); + } + if ((-point[2] + topnode_bbox.min[2]) > stepmax) { + return Big(); + } + if ((point[0] - topnode_bbox.max[0]) > stepmax) { + return Big(); + } + if ((point[1] - topnode_bbox.max[1]) > stepmax) { + return Big(); + } + if ((point[2] - topnode_bbox.max[2]) > stepmax) { + return Big(); + } + + // the ray used for bvh interaction + Ray ray(Vec3(point[0], point[1], point[2]), // origin + Vec3(dir[0], dir[1], dir[2]), // direction + 0.0f, // minimum distance (could give stepmax ?) + truncate_roundup(local_step)); + + static constexpr bool use_robust_traversal = true; + + Vertex_t dir_v{dir[0], dir[1], dir[2]}; + // Traverse the BVH and apply concrete object intersection in BVH leafs + bvh::v2::GrowingStack stack; + mybvh->intersect(ray, mybvh->get_root().index, stack, [&](size_t begin, size_t end) { + for (size_t prim_id = begin; prim_id < end; ++prim_id) { + auto objectid = mybvh->prim_ids[prim_id]; + const auto& facet = fFacets[objectid]; + const auto& n = fOutwardNormals[objectid]; + + // quick normal test. Coming from outside, the dot product must be negative + if (n.Dot(dir_v) > 0.) { + continue; + } + + auto thisdist = rayTriangle(Vertex_t(point[0], point[1], point[2]), dir_v, + fVertices[facet[0]], fVertices[facet[1]], fVertices[facet[2]], 0.); + + if (thisdist < local_step) { + local_step = thisdist; + } + } + return false; // go on after this + }); + + return local_step; +} + +//////////////////////////////////////////////////////////////////////////////// +/// DistFromOutside + +Double_t O2Tessellated::DistFromInside(const Double_t* point, const Double_t* dir, Int_t /*iact*/, Double_t /*stepmax*/, + Double_t* /*safe*/) const +{ + // use the BVH intersector in combination with leaf ray-triangle testing + double local_step = Big(); // we need this otherwise the lambda get's confused + + using Scalar = float; + using Vec3 = bvh::v2::Vec; + using Node = bvh::v2::Node; + using Bvh = bvh::v2::Bvh; + using Ray = bvh::v2::Ray; + + // let's fetch the bvh + auto mybvh = (Bvh*)fBVH; + if (!mybvh) { + assert(false); + return -1.; + } + + auto truncate_roundup = [](double orig) { + float epsilon = std::numeric_limits::epsilon() * std::fabs(orig); + // Add the bias to x before assigning it to y + return static_cast(orig + epsilon); + }; + + // the ray used for bvh interaction + Ray ray(Vec3(point[0], point[1], point[2]), // origin + Vec3(dir[0], dir[1], dir[2]), // direction + 0., // minimum distance (could give stepmax ?) + truncate_roundup(local_step)); + + static constexpr bool use_robust_traversal = true; + + Vertex_t dir_v{dir[0], dir[1], dir[2]}; + // Traverse the BVH and apply concrete object intersection in BVH leafs + bvh::v2::GrowingStack stack; + mybvh->intersect(ray, mybvh->get_root().index, stack, [&](size_t begin, size_t end) { + for (size_t prim_id = begin; prim_id < end; ++prim_id) { + auto objectid = mybvh->prim_ids[prim_id]; + auto facet = fFacets[objectid]; + const auto& n = fOutwardNormals[objectid]; + + // Only exiting surfaces are relevant (from inside--> dot product must be positive) + if (n.Dot(dir_v) <= 0.) { + continue; + } + + const auto& v0 = fVertices[facet[0]]; + const auto& v1 = fVertices[facet[1]]; + const auto& v2 = fVertices[facet[2]]; + + const double t = + rayTriangle(Vertex_t{point[0], point[1], point[2]}, dir_v, v0, v1, v2, 0.); + if (t < local_step) { + local_step = t; + } + } + return false; // go on after this + }); + + return local_step; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Capacity + +Double_t O2Tessellated::Capacity() const +{ + // For explanation of the following algorithm see: + // https://en.wikipedia.org/wiki/Polyhedron#Volume + // http://wwwf.imperial.ac.uk/~rn/centroid.pdf + + double vol = 0.0; + for (size_t i = 0; i < fFacets.size(); ++i) { + auto& facet = fFacets[i]; + auto a = fVertices[facet[0]]; + auto b = fVertices[facet[1]]; + auto c = fVertices[facet[2]]; + vol += + a[0] * (b[1] * c[2] - b[2] * c[1]) + b[0] * (c[1] * a[2] - c[2] * a[1]) + c[0] * (a[1] * b[2] - a[2] * b[1]); + } + return vol / 6.0; +} + +//////////////////////////////////////////////////////////////////////////////// +/// BuildBVH + +void O2Tessellated::BuildBVH() +{ + using Scalar = float; + using BBox = bvh::v2::BBox; + using Vec3 = bvh::v2::Vec; + using Node = bvh::v2::Node; + using Bvh = bvh::v2::Bvh; + + // helper determining axis aligned bounding box from a facet; + auto GetBoundingBox = [this](TGeoFacet const& facet) { +#ifndef NDEBUG + const auto nvertices = facet.GetNvert(); + assert(nvertices == 3); // for now only triangles +#endif + const auto& v1 = fVertices[facet[0]]; + const auto& v2 = fVertices[facet[1]]; + const auto& v3 = fVertices[facet[2]]; + BBox bbox; + bbox.min[0] = std::min(std::min(v1[0], v2[0]), v3[0]) - 0.001f; + bbox.min[1] = std::min(std::min(v1[1], v2[1]), v3[1]) - 0.001f; + bbox.min[2] = std::min(std::min(v1[2], v2[2]), v3[2]) - 0.001f; + bbox.max[0] = std::max(std::max(v1[0], v2[0]), v3[0]) + 0.001f; + bbox.max[1] = std::max(std::max(v1[1], v2[1]), v3[1]) + 0.001f; + bbox.max[2] = std::max(std::max(v1[2], v2[2]), v3[2]) + 0.001f; + return bbox; + }; + + // we need bounding boxes enclosing the primitives and centers of primitives + // (replaced here by centers of bounding boxes) to build the bvh + std::vector bboxes; + std::vector centers; + + // loop over all the triangles/Facets; + int nd = fFacets.size(); + for (int i = 0; i < nd; ++i) { + auto& facet = fFacets[i]; + + // fetch the bounding box of this node and add to the vector of bounding boxes + (bboxes).push_back(GetBoundingBox(facet)); + centers.emplace_back((bboxes).back().get_center()); + } + + // check if some previous object is registered and delete if necessary + if (fBVH) { + delete (Bvh*)fBVH; + fBVH = nullptr; + } + + // create the bvh + typename bvh::v2::DefaultBuilder::Config config; + config.quality = bvh::v2::DefaultBuilder::Quality::High; + auto bvh = bvh::v2::DefaultBuilder::build(bboxes, centers, config); + auto bvhptr = new Bvh; + *bvhptr = std::move(bvh); // copy structure + fBVH = (void*)(bvhptr); + + return; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Contains + +bool O2Tessellated::Contains(Double_t const* point) const +{ + // we do the parity test + using Scalar = float; + using Vec3 = bvh::v2::Vec; + using Node = bvh::v2::Node; + using Bvh = bvh::v2::Bvh; + using Ray = bvh::v2::Ray; + + // let's fetch the bvh + auto mybvh = (Bvh*)fBVH; + if (!mybvh) { + assert(false); + return false; + } + + auto truncate_roundup = [](double orig) { + float epsilon = std::numeric_limits::epsilon() * std::fabs(orig); + // Add the bias to x before assigning it to y + return static_cast(orig + epsilon); + }; + + // let's do very quick checks against the top node + if (!TGeoBBox::Contains(point)) { + return false; + } + + // An arbitrary test direction. + // Doesn't need to be normalized and probes all normals. Also ensuring to be skewed somewhat + // without evident symmetries. + Vertex_t test_dir{1.0, 1.41421356237, 1.73205080757}; + + double local_step = Big(); + // the ray used for bvh interaction + Ray ray(Vec3(point[0], point[1], point[2]), // origin + Vec3(test_dir[0], test_dir[1], test_dir[2]), // direction + 0.0f, // minimum distance (could give stepmax ?) + truncate_roundup(local_step)); + + static constexpr bool use_robust_traversal = true; + + // Traverse the BVH and apply concrete object intersection in BVH leafs + bvh::v2::GrowingStack stack; + size_t crossings = 0; + mybvh->intersect(ray, mybvh->get_root().index, stack, [&](size_t begin, size_t end) { + for (size_t prim_id = begin; prim_id < end; ++prim_id) { + auto objectid = mybvh->prim_ids[prim_id]; + auto& facet = fFacets[objectid]; + + // for the parity test, we probe all crossing surfaces + const auto& v0 = fVertices[facet[0]]; + const auto& v1 = fVertices[facet[1]]; + const auto& v2 = fVertices[facet[2]]; + + const double t = rayTriangle(Vertex_t(point[0], point[1], point[2]), + test_dir, v0, v1, v2, 0.); + + if (t != std::numeric_limits::infinity()) { + ++crossings; + } + } + return false; + }); + + return crossings & 1; +} + +namespace +{ + +// Helper classes/structs used for priority queue - BVH traversal +// structure keeping cost (value) for a BVH index +struct BVHPrioElement { + size_t bvh_node_id; + float value; +}; + +// A priority queue for BVHPrioElement with an additional clear method +// for quick reset. We intentionally derive from std::priority_queue here to expose a +// clear() convenience method via access to the protected container `c`. +// This is internal, non-polymorphic code and relies on standard-library +// implementation details that are stable across supported platforms. +template +class BVHPrioQueue : public std::priority_queue, Comparator> +{ + public: + using std::priority_queue, + Comparator>::priority_queue; // constructor inclusion + + // convenience method to quickly clear/reset the queue (instead of having to pop one by one) + void clear() { this->c.clear(); } +}; + +} // namespace + +/// a reusable safety kernel, which optionally returns the closest face +template +inline Double_t O2Tessellated::SafetyKernel(const Double_t* point, bool in, int* closest_facet_id) const +{ + // This is the classic traversal/pruning of a BVH based on priority queue search + + float smallest_safety_sq = TGeoShape::Big(); + + using Scalar = float; + using Vec3 = bvh::v2::Vec; + using Node = bvh::v2::Node; + using Bvh = bvh::v2::Bvh; + + // let's fetch the bvh + auto mybvh = (Bvh*)fBVH; + + // testpoint object in float for quick BVH interaction + Vec3 testpoint(point[0], point[1], point[2]); + + auto currnode = mybvh->nodes[0]; // we start from the top BVH node + // we do a quick check on the top node (in case we are outside shape) + bool outside_top = false; + if (!in) { + outside_top = !bvh::v2::extra::contains(currnode.get_bbox(), testpoint); + if (outside_top) { + const auto safety_sq_to_top = bvh::v2::extra::SafetySqToNode(currnode.get_bbox(), testpoint); + // we simply return safety to the outer bounding box as an estimate + return std::sqrt(safety_sq_to_top); + } + } + + // comparator bringing out "smallest" value on top + auto cmp = [](BVHPrioElement a, BVHPrioElement b) { return a.value > b.value; }; + static thread_local BVHPrioQueue queue(cmp); + queue.clear(); + + // algorithm is based on standard iterative tree traversal with priority queues + float current_safety_to_node_sq = 0.f; + + if (returnFace) { + *closest_facet_id = -1; + } + + do { + if (currnode.is_leaf()) { + // we are in a leaf node and actually talk to a face/triangular primitive + const auto begin_prim_id = currnode.index.first_id(); + const auto end_prim_id = begin_prim_id + currnode.index.prim_count(); + + for (auto p_id = begin_prim_id; p_id < end_prim_id; p_id++) { + const auto object_id = mybvh->prim_ids[p_id]; + + const auto& facet = fFacets[object_id]; + const auto& v1 = fVertices[facet[0]]; + const auto& v2 = fVertices[facet[1]]; + const auto& v3 = fVertices[facet[2]]; + + auto thissafetySQ = pointTriangleDistSq(Vec3f{point[0], point[1], point[2]}, Vec3f{v1[0], v1[1], v1[2]}, + Vec3f{v2[0], v2[1], v2[2]}, Vec3f{v3[0], v3[1], v3[2]}); + + if (thissafetySQ < smallest_safety_sq) { + smallest_safety_sq = thissafetySQ; + if (returnFace) { + *closest_facet_id = object_id; + } + } + } + } else { + // not a leave node ... for further traversal, + // we inject the children into priority queue based on distance to it's bounding box + const auto leftchild_id = currnode.index.first_id(); + const auto rightchild_id = leftchild_id + 1; + + for (size_t childid : {leftchild_id, rightchild_id}) { + if (childid >= mybvh->nodes.size()) { + continue; + } + + const auto& node = mybvh->nodes[childid]; + const auto inside = bvh::v2::extra::contains(node.get_bbox(), testpoint); + + if (inside) { + // this must be further considered because we are inside the bounding box + queue.push(BVHPrioElement{childid, -1.}); + } else { + auto safety_to_node_square = bvh::v2::extra::SafetySqToNode(node.get_bbox(), testpoint); + if (safety_to_node_square <= smallest_safety_sq) { + // this should be further considered + queue.push(BVHPrioElement{childid, safety_to_node_square}); + } + } + } + } + + if (queue.size() > 0) { + auto currElement = queue.top(); + currnode = mybvh->nodes[currElement.bvh_node_id]; + current_safety_to_node_sq = currElement.value; + queue.pop(); + } else { + break; + } + } while (current_safety_to_node_sq <= smallest_safety_sq); + + return std::nextafter(std::sqrt(smallest_safety_sq), 0.0f); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Safety + +Double_t O2Tessellated::Safety(const Double_t* point, Bool_t in) const +{ + // we could use some caching here (in future) since queries to the solid will likely + // be made with some locality + + // fall-back to precise safety kernel + return SafetyKernel(point, in); +} + +//////////////////////////////////////////////////////////////////////////////// +/// ComputeNormal interface + +void O2Tessellated::ComputeNormal(const Double_t* point, const Double_t* dir, Double_t* norm) const +{ + // We take the approach to identify closest facet to the point via safety + // and returning the normal from this face. + + // TODO: Before doing that we could check for cached points from other queries + + // use safety kernel + int closest_face_id = -1; + SafetyKernel(point, true, &closest_face_id); + + if (closest_face_id < 0) { + norm[0] = 1.; + norm[1] = 0.; + norm[2] = 0.; + return; + } + + const auto& n = fOutwardNormals[closest_face_id]; + norm[0] = n[0]; + norm[1] = n[1]; + norm[2] = n[2]; + + // change sign depending on dir + if (norm[0] * dir[0] + norm[1] * dir[1] + norm[2] * dir[2] < 0) { + norm[0] = -norm[0]; + norm[1] = -norm[1]; + norm[2] = -norm[2]; + } + return; +} + +//////////////////////////////////////////////////////////////////////////////// +/// trivial (non-BVH) DistFromInside function + +Double_t O2Tessellated::DistFromInside_Loop(const Double_t* point, const Double_t* dir) const +{ + Vertex_t p(point[0], point[1], point[2]); + Vertex_t d(dir[0], dir[1], dir[2]); + + double dist = Big(); + for (size_t i = 0; i < fFacets.size(); ++i) { + const auto& facet = fFacets[i]; + const auto& n = fOutwardNormals[i]; + + // Only exiting surfaces are relevant (from inside--> dot product must be positive) + if (n.Dot(d) <= 0.0) { + continue; + } + + const auto& v0 = fVertices[facet[0]]; + const auto& v1 = fVertices[facet[1]]; + const auto& v2 = fVertices[facet[2]]; + + const double t = rayTriangle(p, d, v0, v1, v2, 0.); + + if (t < dist) { + dist = t; + } + } + return dist; +} + +//////////////////////////////////////////////////////////////////////////////// +/// trivial (non-BVH) DistFromOutside function + +Double_t O2Tessellated::DistFromOutside_Loop(const Double_t* point, const Double_t* dir) const +{ + Vertex_t p(point[0], point[1], point[2]); + Vertex_t d(dir[0], dir[1], dir[2]); + + double dist = Big(); + for (size_t i = 0; i < fFacets.size(); ++i) { + const auto& facet = fFacets[i]; + const auto& n = fOutwardNormals[i]; + + // Only exiting surfaces are relevant (from outside, the dot product must be negative) + if (n.Dot(d) > 0.0) { + continue; + } + + const auto& v0 = fVertices[facet[0]]; + const auto& v1 = fVertices[facet[1]]; + const auto& v2 = fVertices[facet[2]]; + + const double t = rayTriangle(p, d, v0, v1, v2, 0.); + + if (t < dist) { + dist = t; + } + } + return dist; +} + +//////////////////////////////////////////////////////////////////////////////// +/// trivial (non-BVH) Contains + +bool O2Tessellated::Contains_Loop(const Double_t* point) const +{ + // Fixed ray direction + const Vertex_t test_dir{1.0, 1.41421356237, 1.73205080757}; + + Vertex_t p(point[0], point[1], point[2]); + + int crossings = 0; + for (size_t i = 0; i < fFacets.size(); ++i) { + const auto& facet = fFacets[i]; + + const auto& v0 = fVertices[facet[0]]; + const auto& v1 = fVertices[facet[1]]; + const auto& v2 = fVertices[facet[2]]; + + const double t = rayTriangle(p, test_dir, v0, v1, v2, 0.); + if (t != std::numeric_limits::infinity()) { + ++crossings; + } + } + return (crossings & 1); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Custom streamer which performs Closing on read. +/// Recalculation of BVH and normals is fast + +void O2Tessellated::Streamer(TBuffer& b) +{ + if (b.IsReading()) { + b.ReadClassBuffer(O2Tessellated::Class(), this); + CloseShape(false); // close shape but do not re-perform checks + } else { + b.WriteClassBuffer(O2Tessellated::Class(), this); + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Calculate the normals + +void O2Tessellated::CalculateNormals() +{ + fOutwardNormals.clear(); + for (auto& facet : fFacets) { + auto& v1 = fVertices[facet[0]]; + auto& v2 = fVertices[facet[1]]; + auto& v3 = fVertices[facet[2]]; + using Vec3d = Vec3f; + auto norm = triangleNormal(Vec3d{v1[0], v1[1], v1[2]}, Vec3d{v2[0], v2[1], v2[2]}, Vec3d{v3[0], v3[1], v3[2]}); + fOutwardNormals.emplace_back(Vertex_t{norm.x, norm.y, norm.z}); + } +} + +// NOLINTEND \ No newline at end of file diff --git a/Detectors/Base/src/Propagator.cxx b/Detectors/Base/src/Propagator.cxx index 754c0c14e6f60..208b9bf138688 100644 --- a/Detectors/Base/src/Propagator.cxx +++ b/Detectors/Base/src/Propagator.cxx @@ -15,6 +15,7 @@ #include "GPUCommonMath.h" #include "GPUTPCGMPolynomialField.h" #include "MathUtils/Utils.h" +#include "ReconstructionDataFormats/HelixHelper.h" #include "ReconstructionDataFormats/Vertex.h" using namespace o2::base; @@ -170,7 +171,7 @@ GPUd() bool PropagatorImpl::PropagateToXBxByBz(TrackParCov_t& track, va signCorr = -dir; // sign of eloss correction is not imposed } - gpu::gpustd::array b{}; + std::array b{}; while (math_utils::detail::abs(dx) > Epsilon) { auto step = math_utils::detail::min(math_utils::detail::abs(dx), maxStep); if (dir < 0) { @@ -217,6 +218,75 @@ GPUd() bool PropagatorImpl::PropagateToXBxByBz(TrackParCov_t& track, va return true; } +//_______________________________________________________________________ +template +GPUd() bool PropagatorImpl::PropagateToXBxByBz(TrackParCov_t& track, TrackPar_t& linRef, value_type xToGo, value_type maxSnp, value_type maxStep, + PropagatorImpl::MatCorrType matCorr, track::TrackLTIntegral* tofInfo, int signCorr) const +{ + //---------------------------------------------------------------- + // + // Propagates the track to the plane X=xk (cm), using linRef as a Kalman linearisation point. + // taking into account all the three components of the magnetic field + // and correcting for the crossed material. + // + // 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) + //---------------------------------------------------------------- + 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 b{}; + while (math_utils::detail::abs(dx) > Epsilon) { + auto step = math_utils::detail::min(math_utils::detail::abs(dx), maxStep); + if (dir < 0) { + step = -step; + } + auto x = track.getX() + step; + auto xyz0 = linRef.getXYZGlo(); + getFieldXYZ(xyz0, &b[0]); + + auto correct = [&track, &linRef, &xyz0, tofInfo, matCorr, signCorr, this]() { + bool res = true; + if (matCorr != MatCorrType::USEMatCorrNONE) { + auto xyz1 = linRef.getXYZGlo(); + auto mb = this->getMatBudget(matCorr, xyz0, xyz1); + if (!track.correctForMaterial(linRef, mb.meanX2X0, mb.getXRho(signCorr))) { + res = false; + } + if (tofInfo) { + tofInfo->addStep(mb.length, linRef.getQ2P2()); // 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 = linRef.getXYZGlo(); + math_utils::Vector3D stepV(xyz1.X() - xyz0.X(), xyz1.Y() - xyz0.Y(), xyz1.Z() - xyz0.Z()); + tofInfo->addStep(stepV.R(), linRef.getQ2P2()); + } + return res; + }; + + if (!track.propagateTo(x, linRef, b)) { + return false; + } + if (maxSnp > 0 && math_utils::detail::abs(track.getSnp()) >= maxSnp) { + correct(); + return false; + } + if (!correct()) { + return false; + } + dx = xToGo - track.getX(); + } + track.setX(xToGo); + return true; +} + //_______________________________________________________________________ template GPUd() bool PropagatorImpl::PropagateToXBxByBz(TrackPar_t& track, value_type xToGo, value_type maxSnp, value_type maxStep, @@ -239,7 +309,7 @@ GPUd() bool PropagatorImpl::PropagateToXBxByBz(TrackPar_t& track, value signCorr = -dir; // sign of eloss correction is not imposed } - gpu::gpustd::array b{}; + std::array b{}; while (math_utils::detail::abs(dx) > Epsilon) { auto step = math_utils::detail::min(math_utils::detail::abs(dx), maxStep); if (dir < 0) { @@ -294,8 +364,7 @@ GPUd() bool PropagatorImpl::propagateToX(TrackParCov_t& track, value_ty //---------------------------------------------------------------- // // Propagates the track to the plane X=xk (cm) - // taking into account all the three components of the magnetic field - // and correcting for the crossed material. + // Use bz only and correct for the crossed material. // // maxStep - maximal step for propagation // tofInfo - optional container for track length and PID-dependent TOF integration @@ -351,6 +420,72 @@ GPUd() bool PropagatorImpl::propagateToX(TrackParCov_t& track, value_ty return true; } +//_______________________________________________________________________ +template +GPUd() bool PropagatorImpl::propagateToX(TrackParCov_t& track, TrackPar_t& linRef, value_type xToGo, value_type bZ, value_type maxSnp, value_type maxStep, + PropagatorImpl::MatCorrType matCorr, track::TrackLTIntegral* tofInfo, int signCorr) const +{ + //---------------------------------------------------------------- + // + // Propagates the track to the plane X=xk (cm), using linRef as a Kalman linearisation point. + // Use bz only and correct for the crossed material if requested. + // + // 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) + //---------------------------------------------------------------- + auto dx = xToGo - track.getX(); + int dir = dx > 0.f ? 1 : -1; + if (!signCorr) { + signCorr = -dir; // sign of eloss correction is not imposed + } + + while (math_utils::detail::abs(dx) > Epsilon) { + auto step = math_utils::detail::min(math_utils::detail::abs(dx), maxStep); + if (dir < 0) { + step = -step; + } + auto x = track.getX() + step; + auto xyz0 = linRef.getXYZGlo(); + + auto correct = [&track, &linRef, &xyz0, tofInfo, matCorr, signCorr, this]() { + bool res = true; + if (matCorr != MatCorrType::USEMatCorrNONE) { + auto xyz1 = linRef.getXYZGlo(); + auto mb = this->getMatBudget(matCorr, xyz0, xyz1); + if (!track.correctForMaterial(linRef, mb.meanX2X0, mb.getXRho(signCorr))) { + res = false; + } + if (tofInfo) { + tofInfo->addStep(mb.length, linRef.getQ2P2()); // 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 = linRef.getXYZGlo(); + math_utils::Vector3D stepV(xyz1.X() - xyz0.X(), xyz1.Y() - xyz0.Y(), xyz1.Z() - xyz0.Z()); + tofInfo->addStep(stepV.R(), linRef.getQ2P2()); + } + return res; + }; + + if (!track.propagateTo(x, linRef, bZ)) { // linRef also updated + return false; + } + if (maxSnp > 0 && math_utils::detail::abs(track.getSnp()) >= maxSnp) { + correct(); + return false; + } + if (!correct()) { + return false; + } + dx = xToGo - track.getX(); + } + track.setX(xToGo); + return true; +} + //_______________________________________________________________________ template GPUd() bool PropagatorImpl::propagateToX(TrackPar_t& track, value_type xToGo, value_type bZ, value_type maxSnp, value_type maxStep, @@ -418,6 +553,118 @@ GPUd() bool PropagatorImpl::propagateToX(TrackPar_t& track, value_type return true; } +//_______________________________________________________________________ +template +template +GPUd() bool PropagatorImpl::propagateToR(track_T& track, value_type r, bool bzOnly, value_type maxSnp, value_type maxStep, + MatCorrType matCorr, track::TrackLTIntegral* tofInfo, int signCorr) const +{ + const value_T MaxPhiLoc = math_utils::detail::asin(maxSnp), MaxPhiLocSafe = 0.95 * MaxPhiLoc; + auto bz = getNominalBz(); + if (math_utils::detail::abs(bz) > constants::math::Almost0) { + o2::track::TrackAuxPar traux(track, bz); + o2::track::TrackAuxPar crad; + value_type r0 = math_utils::detail::sqrt(track.getX() * track.getX() + track.getY() * track.getY()); + value_type dr = (r - r0); + value_type rTmp = r - (math_utils::detail::abs(dr) > 1. ? (dr > 0 ? 0.5 : -0.5) : 0.5 * dr); // 1st propagate a few mm short of the targer R + crad.rC = rTmp; + crad.c = crad.cc = 1.f; + crad.s = crad.ss = crad.cs = 0.f; + o2::track::CrossInfo cross; + cross.circlesCrossInfo(crad, traux, 0.); + if (cross.nDCA < 1) { + return false; + } + double phiCross[2] = {}, dphi[2] = {}; + auto curv = track.getCurvature(bz); + bool clockwise = curv < 0; // q+ in B+ or q- in B- goes clockwise + auto phiLoc = math_utils::detail::asin(track.getSnp()); + auto phi0 = phiLoc + track.getAlpha(); + o2::math_utils::detail::bringTo02Pi(phi0); + for (int i = 0; i < cross.nDCA; i++) { + // track pT direction angle at crossing points: + // == angle of the tangential to track circle at the crossing point X,Y + // == normal to the radial vector from the track circle center {X-cX, Y-cY} + // i.e. the angle of the vector {Y-cY, -(X-cx)} + auto normX = double(cross.yDCA[i]) - double(traux.yC), normY = -(double(cross.xDCA[i]) - double(traux.xC)); + if (!clockwise) { + normX = -normX; + normY = -normY; + } + phiCross[i] = math_utils::detail::atan2(normY, normX); + o2::math_utils::detail::bringTo02Pi(phiCross[i]); + dphi[i] = phiCross[i] - phi0; + if (dphi[i] > o2::constants::math::PI) { + dphi[i] -= o2::constants::math::TwoPI; + } else if (dphi[i] < -o2::constants::math::PI) { + dphi[i] += o2::constants::math::TwoPI; + } + } + int sel = cross.nDCA == 1 ? 0 : (clockwise ? (dphi[0] < dphi[1] ? 0 : 1) : (dphi[1] < dphi[0] ? 0 : 1)); + auto deltaPhi = dphi[sel]; + + while (1) { + auto phiLocFin = phiLoc + deltaPhi; + // case1 + if (math_utils::detail::abs(phiLocFin) < MaxPhiLocSafe) { // just 1 step propagation + auto deltaX = (math_utils::detail::sin(phiLocFin) - track.getSnp()) / track.getCurvature(bz); + if (!propagateTo(track, track.getX() + deltaX, bzOnly, maxSnp, maxStep, matCorr, tofInfo, signCorr)) { + return false; + } + break; + } + if (math_utils::detail::abs(deltaPhi) < (2 * MaxPhiLocSafe)) { // still can go in 1 step with one extra rotation + auto rot = phiLoc + 0.5 * deltaPhi; + if (!track.rotate(track.getAlpha() + rot)) { + return false; + } + phiLoc -= rot; + continue; // should be ok for the case 1 now. + } + + auto rot = phiLoc + (deltaPhi > 0 ? MaxPhiLocSafe : -MaxPhiLocSafe); + if (!track.rotate(track.getAlpha() + rot)) { + return false; + } + phiLoc -= rot; // = +- MaxPhiLocSafe + + // propagate to phiLoc = +-MaxPhiLocSafe + auto tgtPhiLoc = deltaPhi > 0 ? MaxPhiLocSafe : -MaxPhiLocSafe; + auto deltaX = (math_utils::detail::sin(tgtPhiLoc) - track.getSnp()) / track.getCurvature(bz); + if (!propagateTo(track, track.getX() + deltaX, bzOnly, maxSnp, maxStep, matCorr, tofInfo, signCorr)) { + return false; + } + deltaPhi -= tgtPhiLoc - phiLoc; + phiLoc = deltaPhi > 0 ? MaxPhiLocSafe : -MaxPhiLocSafe; + continue; // should be of for the case 1 now. + } + bz = getBz(math_utils::Point3D{value_type(cross.xDCA[sel]), value_type(cross.yDCA[sel]), value_type(track.getZ())}); + } + // do final step till target R, also covers Bz = 0; + value_type xfin; + if (!track.getXatLabR(r, xfin, bz)) { + return false; + } + return propagateToX(track, xfin, bzOnly, maxSnp, maxStep, matCorr, tofInfo, signCorr); +} + +template +GPUd() bool PropagatorImpl::propagateToAlphaX(TrackParCov_t& track, TrackPar_t* linRef, value_type alpha, value_type x, bool bzOnly, value_type maxSnp, value_type maxStep, int minSteps, + MatCorrType matCorr, track::TrackLTIntegral* tofInfo, int signCorr) const +{ + // propagate to alpha,X, if needed in a few steps + auto snp = track.getSnpAt(alpha, x, getNominalBz()); + // apply safety factor 0.9 for crude rotation estimate + if (math_utils::detail::abs(snp) < maxSnp * 0.9 && (linRef ? track.rotate(alpha, *linRef, getNominalBz()) : track.rotate(alpha))) { + auto dx = math_utils::detail::abs(x - track.getX()); + if (dx < Epsilon) { + return true; + } + return propagateTo(track, linRef, x, bzOnly, maxSnp, math_utils::detail::min(dx / minSteps, maxStep), matCorr, tofInfo, signCorr); + } + return false; +} + //_______________________________________________________________________ template template @@ -468,6 +715,10 @@ GPUd() bool PropagatorImpl::propagateToDCA(const o2::dataformats::Verte // Estimate the impact parameter neglecting the track curvature value_type d = math_utils::detail::abs(x * snp - y * csp); if (d > maxD) { + if (dca) { // provide default DCA for failed propag + dca->set(o2::track::DefaultDCA, o2::track::DefaultDCA, + o2::track::DefaultDCACov, o2::track::DefaultDCACov, o2::track::DefaultDCACov); + } return false; } value_type crv = track.getCurvature(bZ); @@ -488,6 +739,10 @@ GPUd() bool PropagatorImpl::propagateToDCA(const o2::dataformats::Verte #elif !defined(GPUCA_NO_FMT) LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << vtx; #endif + if (dca) { // provide default DCA for failed propag + dca->set(o2::track::DefaultDCA, o2::track::DefaultDCA, + o2::track::DefaultDCACov, o2::track::DefaultDCACov, o2::track::DefaultDCACov); + } return false; } track = tmpT; @@ -517,6 +772,10 @@ GPUd() bool PropagatorImpl::propagateToDCABxByBz(const o2::dataformats: // Estimate the impact parameter neglecting the track curvature value_type d = math_utils::detail::abs(x * snp - y * csp); if (d > maxD) { + if (dca) { // provide default DCA for failed propag + dca->set(o2::track::DefaultDCA, o2::track::DefaultDCA, + o2::track::DefaultDCACov, o2::track::DefaultDCACov, o2::track::DefaultDCACov); + } return false; } value_type crv = track.getCurvature(mNominalBz); @@ -537,6 +796,10 @@ GPUd() bool PropagatorImpl::propagateToDCABxByBz(const o2::dataformats: #elif !defined(GPUCA_NO_FMT) LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << vtx; #endif + if (dca) { // provide default DCA for failed propag + dca->set(o2::track::DefaultDCA, o2::track::DefaultDCA, + o2::track::DefaultDCACov, o2::track::DefaultDCACov, o2::track::DefaultDCACov); + } return false; } track = tmpT; @@ -553,7 +816,7 @@ GPUd() bool PropagatorImpl::propagateToDCABxByBz(const o2::dataformats: template GPUd() bool PropagatorImpl::propagateToDCA(const math_utils::Point3D& vtx, TrackPar_t& track, value_type bZ, value_type maxStep, PropagatorImpl::MatCorrType matCorr, - gpu::gpustd::array* dca, track::TrackLTIntegral* tofInfo, + std::array* dca, track::TrackLTIntegral* tofInfo, int signCorr, value_type maxD) const { // propagate track to DCA to the vertex @@ -566,6 +829,10 @@ GPUd() bool PropagatorImpl::propagateToDCA(const math_utils::Point3D(x * snp - y * csp); if (d > maxD) { + if (dca) { // provide default DCA for failed propag + (*dca)[0] = o2::track::DefaultDCA; + (*dca)[1] = o2::track::DefaultDCA; + } return false; } value_type crv = track.getCurvature(bZ); @@ -587,6 +854,10 @@ GPUd() bool PropagatorImpl::propagateToDCA(const math_utils::Point3D::propagateToDCA(const math_utils::Point3D GPUd() bool PropagatorImpl::propagateToDCABxByBz(const math_utils::Point3D& vtx, TrackPar_t& track, value_type maxStep, PropagatorImpl::MatCorrType matCorr, - gpu::gpustd::array* dca, track::TrackLTIntegral* tofInfo, + std::array* dca, track::TrackLTIntegral* tofInfo, int signCorr, value_type maxD) const { // propagate track to DCA to the vertex @@ -614,6 +885,10 @@ GPUd() bool PropagatorImpl::propagateToDCABxByBz(const math_utils::Poin // Estimate the impact parameter neglecting the track curvature value_type d = math_utils::detail::abs(x * snp - y * csp); if (d > maxD) { + if (dca) { // provide default DCA for failed propag + (*dca)[0] = o2::track::DefaultDCA; + (*dca)[1] = o2::track::DefaultDCA; + } return false; } value_type crv = track.getCurvature(mNominalBz); @@ -635,6 +910,10 @@ GPUd() bool PropagatorImpl::propagateToDCABxByBz(const math_utils::Poin #else LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << " for vertex " << vtx.X() << ' ' << vtx.Y() << ' ' << vtx.Z(); #endif + if (dca) { // provide default DCA for failed propag + (*dca)[0] = o2::track::DefaultDCA; + (*dca)[1] = o2::track::DefaultDCA; + } return false; } track = tmpT; @@ -772,6 +1051,35 @@ GPUd() void PropagatorImpl::getFieldXYZImpl(const math_utils::Point3D +template +GPUd() T PropagatorImpl::getBzImpl(const math_utils::Point3D xyz) const +{ + T bz = 0; + 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 + constexpr value_type kCLight1 = 1. / o2::gpu::gpu_common_constants::kCLight; + bz = f->GetFieldBz(xyz.X(), xyz.Y(), xyz.Z()) * kCLight1; + } else { +#ifndef GPUCA_GPUCODE + if (mFieldFast) { + mFieldFast->GetBz(xyz, bz); // 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 + bz = mField->GetBz(xyz.X(), xyz.Y(), xyz.Z()); +#endif + } +#endif + } + return bz; +} + template GPUd() void PropagatorImpl::getFieldXYZ(const math_utils::Point3D xyz, float* bxyz) const { @@ -784,12 +1092,26 @@ GPUd() void PropagatorImpl::getFieldXYZ(const math_utils::Point3D(xyz, bxyz); } +template +GPUd() float PropagatorImpl::getBz(const math_utils::Point3D xyz) const +{ + return getBzImpl(xyz); +} + +template +GPUd() double PropagatorImpl::getBz(const math_utils::Point3D xyz) const +{ + return getBzImpl(xyz); +} + namespace o2::base { #if !defined(GPUCA_GPUCODE) || defined(GPUCA_GPUCODE_DEVICE) // FIXME: DR: WORKAROUND to avoid CUDA bug creating host symbols for device code. template class PropagatorImpl; template bool GPUdni() PropagatorImpl::propagateToAlphaX::TrackPar_t>(PropagatorImpl::TrackPar_t&, float, float, bool, float, float, int, PropagatorImpl::MatCorrType matCorr, track::TrackLTIntegral*, int) const; template bool GPUdni() PropagatorImpl::propagateToAlphaX::TrackParCov_t>(PropagatorImpl::TrackParCov_t&, float, float, bool, float, float, int, PropagatorImpl::MatCorrType matCorr, track::TrackLTIntegral*, int) const; +template bool GPUdni() PropagatorImpl::propagateToR::TrackPar_t>(PropagatorImpl::TrackPar_t&, float, bool, float, float, PropagatorImpl::MatCorrType matCorr, track::TrackLTIntegral*, int) const; +template bool GPUdni() PropagatorImpl::propagateToR::TrackParCov_t>(PropagatorImpl::TrackParCov_t&, float, bool, float, float, PropagatorImpl::MatCorrType matCorr, track::TrackLTIntegral*, int) const; #endif #ifndef GPUCA_GPUCODE template class PropagatorImpl; diff --git a/Detectors/Base/src/TFIDInfoHelper.cxx b/Detectors/Base/src/TFIDInfoHelper.cxx index f0bd8c0f15a30..6eac1cc18c81a 100644 --- a/Detectors/Base/src/TFIDInfoHelper.cxx +++ b/Detectors/Base/src/TFIDInfoHelper.cxx @@ -23,15 +23,9 @@ void o2::base::TFIDInfoHelper::fillTFIDInfo(ProcessingContext& pc, o2::dataforma { const auto& tinfo = pc.services().get(); static int errCount = 0; - if (tinfo.firstTForbit == -1U || tinfo.creation == -1) { - if (errCount++ < 5) { - LOGP(warn, "Ignoring dummy input with orbit {} and creation time {} in fillTFIDInfo", tinfo.firstTForbit, tinfo.creation); - } - return; + ti.fill(tinfo.firstTForbit, tinfo.tfCounter, tinfo.runNumber, tinfo.timeslice, tinfo.creation); + if (ti.discard && errCount++ < 5) { + LOGP(warn, "Bad input with orbit {}, TFcounter {} and creation time {} in fillTFIDInfo", tinfo.firstTForbit, tinfo.tfCounter, tinfo.creation); } - ti.firstTForbit = tinfo.firstTForbit; - ti.tfCounter = tinfo.tfCounter; - ti.runNumber = tinfo.runNumber; - ti.startTime = tinfo.timeslice; - ti.creation = tinfo.creation; + return; } diff --git a/Detectors/Base/src/TGeoGeometryUtils.cxx b/Detectors/Base/src/TGeoGeometryUtils.cxx new file mode 100644 index 0000000000000..6f06eff17a6d7 --- /dev/null +++ b/Detectors/Base/src/TGeoGeometryUtils.cxx @@ -0,0 +1,144 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TGeoGeometryUtils.cxx +/// \author Sandro Wenzel (CERN) +/// \brief Collection of utility functions for TGeo + +#include +#include +#include +#include +#include + +namespace o2 +{ +namespace base +{ + +namespace +{ +// some helpers to interpret TGeo TBuffer3D output +// and convert it to surface triangles (reengineered from TGeo code) + +std::vector BuildVertexLoop(const TBuffer3D& buf, + const std::vector& segs) +{ + // adjacency list + std::unordered_map> adj; + + for (int s : segs) { + int a = buf.fSegs[3 * s + 1]; + int b = buf.fSegs[3 * s + 2]; + adj[a].push_back(b); + adj[b].push_back(a); + } + + // start from any vertex + int start = adj.begin()->first; + int prev = -1; + int curr = start; + + std::vector loop; + + while (true) { + loop.push_back(curr); + + const auto& nbrs = adj[curr]; + int next = -1; + + for (int n : nbrs) { + if (n != prev) { + next = n; + break; + } + } + + if (next == -1 || next == start) { + break; + } + + prev = curr; + curr = next; + } + return loop; +} + +std::vector> ExtractPolygons(const TBuffer3D& buf) +{ + std::vector> polys; + Int_t idx = 0; + + for (Int_t ip = 0; ip < buf.NbPols(); ++ip) { + + idx++; // color + Int_t nseg = buf.fPols[idx++]; + + std::vector segs(nseg); + for (Int_t i = 0; i < nseg; ++i) { + segs[i] = buf.fPols[idx++]; + } + + auto verts = BuildVertexLoop(buf, segs); + if (verts.size() >= 3) { + polys.push_back(std::move(verts)); + } + } + + return polys; +} + +std::vector> + Triangulate(const std::vector>& polys) +{ + std::vector> tris; + for (const auto& poly : polys) { + int nv = poly.size(); + if (nv < 3) { + continue; + } + + int v0 = poly[0]; + for (int i = 1; i < nv - 1; ++i) { + tris.push_back({{v0, poly[i], poly[i + 1]}}); + } + } + return tris; +} + +TGeoTessellated* MakeTessellated(const TBuffer3D& buf) +{ + auto polys = ExtractPolygons(buf); + auto tris = Triangulate(polys); + int i = 0; + auto* tess = new TGeoTessellated("tess"); + const Double_t* p = buf.fPnts; + for (auto& t : tris) { + tess->AddFacet( + TGeoTessellated::Vertex_t{p[3 * t[0]], p[3 * t[0] + 1], p[3 * t[0] + 2]}, + TGeoTessellated::Vertex_t{p[3 * t[1]], p[3 * t[1] + 1], p[3 * t[1] + 2]}, + TGeoTessellated::Vertex_t{p[3 * t[2]], p[3 * t[2] + 1], p[3 * t[2] + 2]}); + } + tess->CloseShape(); + return tess; +} +} // end anonymous namespace + +///< Transform any (primitive) TGeoShape to a TGeoTessellated +TGeoTessellated* TGeoGeometryUtils::TGeoShapeToTGeoTessellated(TGeoShape const* shape) +{ + auto& buf = shape->GetBuffer3D(TBuffer3D::kRawSizes | TBuffer3D::kRaw | TBuffer3D::kCore, false); + auto tes = MakeTessellated(buf); + return tes; +} + +} // namespace base +} // namespace o2 diff --git a/Detectors/Base/src/bvh2_extra_kernels.h b/Detectors/Base/src/bvh2_extra_kernels.h new file mode 100644 index 0000000000000..70e43202a53c4 --- /dev/null +++ b/Detectors/Base/src/bvh2_extra_kernels.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. + +// Sandro Wenzel 2026 + +#ifndef ROOT_GEOM_BVH2_EXTRA + +namespace bvh::v2::extra +{ + +// reusable geometry kernels used in multiple places +// for interaction with BVH2 structures + +// determines if a point is inside the bounding box +template +bool contains(bvh::v2::BBox const& box, bvh::v2::Vec const& p) +{ + auto min = box.min; + auto max = box.max; + return (p[0] >= min[0] && p[0] <= max[0]) && (p[1] >= min[1] && p[1] <= max[1]) && + (p[2] >= min[2] && p[2] <= max[2]); +} + +// determines the largest squared distance of point to any of the bounding box corners +template +auto RmaxSqToNode(bvh::v2::BBox const& box, bvh::v2::Vec const& p) +{ + // construct the 8 corners to get the maximal distance + const auto minCorner = box.min; + const auto maxCorner = box.max; + using Vec3 = bvh::v2::Vec; + // these are the corners of the bounding box + const std::array, 8> corners{ + Vec3{minCorner[0], minCorner[1], minCorner[2]}, Vec3{minCorner[0], minCorner[1], maxCorner[2]}, + Vec3{minCorner[0], maxCorner[1], minCorner[2]}, Vec3{minCorner[0], maxCorner[1], maxCorner[2]}, + Vec3{maxCorner[0], minCorner[1], minCorner[2]}, Vec3{maxCorner[0], minCorner[1], maxCorner[2]}, + Vec3{maxCorner[0], maxCorner[1], minCorner[2]}, Vec3{maxCorner[0], maxCorner[1], maxCorner[2]}}; + + T Rmax_sq{0}; + for (const auto& corner : corners) { + float R_sq = 0.; + const auto dx = corner[0] - p[0]; + R_sq += dx * dx; + const auto dy = corner[1] - p[1]; + R_sq += dy * dy; + const auto dz = corner[2] - p[2]; + R_sq += dz * dz; + Rmax_sq = std::max(Rmax_sq, R_sq); + } + return Rmax_sq; +}; + +// determines the minimum squared distance of point to a bounding box ("safey square") +template +auto SafetySqToNode(bvh::v2::BBox const& box, bvh::v2::Vec const& p) +{ + T sqDist{0.0}; + for (int i = 0; i < 3; i++) { + T v = p[i]; + if (v < box.min[i]) { + sqDist += (box.min[i] - v) * (box.min[i] - v); + } else if (v > box.max[i]) { + sqDist += (v - box.max[i]) * (v - box.max[i]); + } + } + return sqDist; +}; + +} // namespace bvh::v2::extra + +#endif \ No newline at end of file diff --git a/Detectors/Base/src/bvh2_third_party.h b/Detectors/Base/src/bvh2_third_party.h new file mode 100644 index 0000000000000..5cf7772269642 --- /dev/null +++ b/Detectors/Base/src/bvh2_third_party.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. + +// Sandro Wenzel 2026 + +#ifndef ROOT_GEOM_BVH2_THIRD_PARTY + +// A single entry header into third-party BVH2 installed in ROOT +// Good place to manage compiler warnings etc. + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wshadow" +#pragma clang diagnostic ignored "-Wpsabi" +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wpsabi" +#pragma GCC diagnostic ignored "-Wall" +#pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC diagnostic ignored "-Wattributes" +#elif defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 5051) +#endif + +#include +#include +#include +#include +#include +#include + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#endif \ No newline at end of file diff --git a/Detectors/Base/test/buildMatBudLUT.C b/Detectors/Base/test/buildMatBudLUT.C index 800597d6166fd..860fcbd5da940 100644 --- a/Detectors/Base/test/buildMatBudLUT.C +++ b/Detectors/Base/test/buildMatBudLUT.C @@ -23,13 +23,11 @@ #include #endif -#ifndef GPUCA_ALIGPUCODE // this part is unvisible on GPU version - o2::base::MatLayerCylSet mbLUT; bool testMBLUT(const std::string& lutFile = "matbud.root"); -bool buildMatBudLUT(int nTst = 30, int maxLr = -1, const std::string& outFile = "matbud.root", const std::string& geomNamePrefix = "o2sim", const std::string& opts = ""); +bool buildMatBudLUT(int nTst = 60, int maxLr = -1, const std::string& outFile = "matbud.root", const std::string& geomName = "o2sim_geometry-aligned.root"); struct LrData { float rMin = 0.f; @@ -249,7 +247,9 @@ void configLayers() // air space between Middle and Outer Barrels zSpanH = 80.f; - lrData.emplace_back(LrData(lrData.back().rMax, 33.5, zSpanH)); + zBin = 10.; + rphiBin = lrData.back().rMax * TMath::Pi() * 2 / 18; + lrData.emplace_back(LrData(lrData.back().rMax, 33.5, zSpanH, zBin, rphiBin)); //=================================================================================== // ITS Outer barrel @@ -259,14 +259,14 @@ void configLayers() zBin = 1.; do { auto rmean = lrData.back().rMax + drStep / 2; - rphiBin = rmean * TMath::Pi() * 2 / (nStave * 10); + rphiBin = rmean * TMath::Pi() * 2 / (nStave * 15); lrData.emplace_back(LrData(lrData.back().rMax, lrData.back().rMax + drStep, zSpanH, zBin, rphiBin)); } while (lrData.back().rMax < 36. - kToler); drStep = 1.; do { auto rmean = lrData.back().rMax + drStep / 2; - rphiBin = rmean * TMath::Pi() * 2 / (nStave * 10); + rphiBin = rmean * TMath::Pi() * 2 / (nStave * 15); lrData.emplace_back(LrData(lrData.back().rMax, lrData.back().rMax + drStep, zSpanH, zBin, rphiBin)); } while (lrData.back().rMax < 38.5 - kToler); @@ -274,14 +274,14 @@ void configLayers() drStep = 0.25; do { auto rmean = lrData.back().rMax + drStep / 2; - rphiBin = rmean * TMath::Pi() * 2 / (nStave * 10); + rphiBin = rmean * TMath::Pi() * 2 / (nStave * 15); lrData.emplace_back(LrData(lrData.back().rMax, lrData.back().rMax + drStep, zSpanH, zBin, rphiBin)); } while (lrData.back().rMax < 41. - kToler); drStep = 1.; do { auto rmean = lrData.back().rMax + drStep / 2; - rphiBin = rmean * TMath::Pi() * 2 / (nStave * 10); + rphiBin = rmean * TMath::Pi() * 2 / (nStave * 15); lrData.emplace_back(LrData(lrData.back().rMax, lrData.back().rMax + drStep, zSpanH, zBin, rphiBin)); } while (lrData.back().rMax < 44. - kToler); @@ -301,21 +301,29 @@ void configLayers() } while (lrData.back().rMax < 55. - kToler); zSpanH = 120.f; - lrData.emplace_back(LrData(lrData.back().rMax, 56.5, zSpanH)); - lrData.emplace_back(LrData(lrData.back().rMax, 60.5, zSpanH)); - lrData.emplace_back(LrData(lrData.back().rMax, 61.5, zSpanH)); + zBin = 10.; + rphiBin = lrData.back().rMax * TMath::Pi() * 2 / 18; + lrData.emplace_back(LrData(lrData.back().rMax, 56.5, zSpanH, zBin, rphiBin)); + + //------------------------------------ + zBin = 1.; + rphiBin = lrData.back().rMax * TMath::Pi() * 2 / 18; + lrData.emplace_back(LrData(lrData.back().rMax, 60.5, zSpanH, zBin, rphiBin)); + rphiBin = lrData.back().rMax * TMath::Pi() * 2 / 18; + lrData.emplace_back(LrData(lrData.back().rMax, 61.5, zSpanH, zBin, rphiBin)); zSpanH = 150.f; - drStep = 3.5; - zBin = 15.; - rphiBin = 10; + drStep = 2; + zBin = 1.; do { + auto rmean = lrData.back().rMax + drStep / 2; + rphiBin = rmean * TMath::Pi() * 2 / (NSect * 2); lrData.emplace_back(LrData(lrData.back().rMax, lrData.back().rMax + drStep, zSpanH, zBin, rphiBin)); } while (lrData.back().rMax < 68.5 - kToler); zSpanH = 250.f; - zBin = 25.; - rphiBin = 5; + zBin = 1.; + rphiBin = 2.5; { auto rmean = (lrData.back().rMax + 76) / 2.; rphiBin = rmean * TMath::Pi() * 2 / (NSect * 2); @@ -335,7 +343,7 @@ void configLayers() zBin = 2; { auto rmean = (lrData.back().rMax + 78.5) / 2; - rphiBin = rmean * TMath::Pi() * 2 / (NSect * 12); + rphiBin = rmean * TMath::Pi() * 2 / (NSect * 24); lrData.emplace_back(LrData(lrData.back().rMax, 84.5, zSpanH, zBin, rphiBin)); } @@ -389,5 +397,3 @@ void configLayers() lrData.emplace_back(LrData(lrData.back().rMax, lrData.back().rMax + drStep, zSpanH, zBin, rphiBin)); } while (lrData.back().rMax < 500); } - -#endif //!_COMPILED_ON_GPU_ diff --git a/Detectors/Base/test/rescaleLUT.C b/Detectors/Base/test/rescaleLUT.C new file mode 100644 index 0000000000000..9e25c796e43d1 --- /dev/null +++ b/Detectors/Base/test/rescaleLUT.C @@ -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. + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include "DetectorsBase/MatLayerCylSet.h" +#include "Framework/Logger.h" +#include "CCDB/BasicCCDBManager.h" +#include +#endif + +// Macro to extract layers covering selected radial range into the separate LUT file. + +void rescaleLUT(o2::base::MatLayerCylSet* src, const std::string& outName) +{ + struct RescRange { + float rMin, rMax, factor; + }; + std::vector task = { + // put here radial ranges in increasing order with corresponding factors to rescale + {0.1f, 6.f, 1.05}, // e.g. rescale layers covering 0.1 rmax) { + LOGP(error, "rMax={:.2f} of range {} is larger then rMin={:.2f} of range {}, must be in increasing order", rmin, il - 1, rmax, il); + return; + } + o2::base::Ray ray(std::max(src->getRMin(), rmin), 0., 0., std::min(src->getRMax(), rmax), 0., 0.); + if (!src->getLayersRange(ray, lmin, lmax)) { + LOGP(error, "No layers found for {:.2f} < r < {:.2f}", rmin, rmax); + return; + } + if (lmin == lmax) { + LOGP(error, "rMax={:.2f} of range {} and rMin={:.2f} of range {}, correspond to the same slice {} with {:.2f}getLayer(lmin).getRMin(), src->getLayer(lmin).getRMax()); + return; + } + } + + for (size_t il = 0; il < task.size(); il++) { + src->scaleLayersByR(task[il].rMin, task[il].rMax, task[il].factor); + } + if (outName.size()) { + src->writeToFile(outName); + } +} + +void rescaleLUT(const std::string& fname) +{ + auto src = o2::base::MatLayerCylSet::loadFromFile(fname); + if (!src) { + LOGP(error, "failed to open source LUT from {}", fname); + return; + } + auto fnameOut = std::regex_replace(fname, std::regex(R"(.root)"), "_rescaled.root"); + rescaleLUT(src, fnameOut); +} + +void rescaleLUT(long timestamp = -1) +{ + auto& mg = o2::ccdb::BasicCCDBManager::instance(); + mg.setTimestamp(timestamp); + auto src = o2::base::MatLayerCylSet::rectifyPtrFromFile(mg.get("GLO/Param/MatLUT")); + if (!src) { + LOGP(error, "failed to open load LUT from CCDB for timestamp {}", timestamp); + return; + } + auto fnameOut = fmt::format("matbudLUT_ts{}_rescaled.root", timestamp); + rescaleLUT(src, fnameOut); +} diff --git a/Detectors/Base/test/testMatBudLUT.cxx b/Detectors/Base/test/testMatBudLUT.cxx index 4daa992368dba..33c3498995c90 100644 --- a/Detectors/Base/test/testMatBudLUT.cxx +++ b/Detectors/Base/test/testMatBudLUT.cxx @@ -21,16 +21,12 @@ namespace o2 { BOOST_AUTO_TEST_CASE(MatBudLUT) { -#ifndef GPUCA_ALIGPUCODE // this part is unvisible on GPU version - // using process specific geometry names in order // to avoid race/conditions with other tests accessing geometry std::string geomPrefix("matBudGeom"); std::string matBudFile("matbud"); matBudFile += std::to_string(getpid()) + ".root"; BOOST_CHECK(buildMatBudLUT(2, 20, matBudFile, geomPrefix + std::to_string(getpid()), "align-geom.mDetectors=none")); // generate LUT - BOOST_CHECK(testMBLUT(matBudFile)); // test LUT manipulations - -#endif //!GPUCA_ALIGPUCODE + BOOST_CHECK(testMBLUT(matBudFile)); // test LUT manipulations } } // namespace o2 diff --git a/Detectors/CPV/calib/macros/makeBadMapFromPedestalRun.C b/Detectors/CPV/calib/macros/makeBadMapFromPedestalRun.C index 3b5af09190fe7..9d62cf1a13baa 100644 --- a/Detectors/CPV/calib/macros/makeBadMapFromPedestalRun.C +++ b/Detectors/CPV/calib/macros/makeBadMapFromPedestalRun.C @@ -75,7 +75,7 @@ void makeBadMapFromPedestalRun(const char* ccdbURI = "http://ccdb-test.cern.ch:8 } o2::ccdb::CcdbApi api; - map metadata; // can be empty + std::map metadata; // can be empty api.init(ccdbURI); // or http://localhost:8080 for a local installation api.storeAsTFileAny(&badMap, "CPV/Calib/BadChannelMap", metadata, timeStamp, timeStamp + 31536000000); } diff --git a/Detectors/CPV/reconstruction/include/CPVReconstruction/CTFCoder.h b/Detectors/CPV/reconstruction/include/CPVReconstruction/CTFCoder.h index e9bd0f7249ef1..4e259c24f44a6 100644 --- a/Detectors/CPV/reconstruction/include/CPVReconstruction/CTFCoder.h +++ b/Detectors/CPV/reconstruction/include/CPVReconstruction/CTFCoder.h @@ -32,10 +32,10 @@ namespace o2 namespace cpv { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::CPV) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::CPV, 1.f, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode data to buffer with CTF diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/EntropyDecoderSpec.h b/Detectors/CPV/workflow/include/CPVWorkflow/EntropyDecoderSpec.h index 09de778360d74..7192b1b2f6353 100644 --- a/Detectors/CPV/workflow/include/CPVWorkflow/EntropyDecoderSpec.h +++ b/Detectors/CPV/workflow/include/CPVWorkflow/EntropyDecoderSpec.h @@ -28,7 +28,7 @@ namespace cpv class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity); + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -41,7 +41,7 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt); } // namespace cpv } // namespace o2 diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/EntropyEncoderSpec.h b/Detectors/CPV/workflow/include/CPVWorkflow/EntropyEncoderSpec.h index 24c229179fe1d..a1851ebb97377 100644 --- a/Detectors/CPV/workflow/include/CPVWorkflow/EntropyEncoderSpec.h +++ b/Detectors/CPV/workflow/include/CPVWorkflow/EntropyEncoderSpec.h @@ -28,7 +28,7 @@ namespace cpv class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR = false); + EntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -42,7 +42,7 @@ class EntropyEncoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); } // namespace cpv } // namespace o2 diff --git a/Detectors/CPV/workflow/src/EntropyDecoderSpec.cxx b/Detectors/CPV/workflow/src/EntropyDecoderSpec.cxx index 7c14dc70dd430..518a646e23cb9 100644 --- a/Detectors/CPV/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/CPV/workflow/src/EntropyDecoderSpec.cxx @@ -25,7 +25,7 @@ namespace o2 namespace cpv { -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); @@ -74,7 +74,7 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"triggers"}, "CPV", "CLUSTERTRIGRECS", 0, Lifetime::Timeframe}, @@ -83,16 +83,17 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) std::vector inputs; inputs.emplace_back("ctf_CPV", "CPV", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_CPV", "CPV", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("CPV/Calib/CTFDictionaryTree")); + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_CPV", "CPV", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("CPV/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ "cpv-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } } // namespace cpv diff --git a/Detectors/CPV/workflow/src/EntropyEncoderSpec.cxx b/Detectors/CPV/workflow/src/EntropyEncoderSpec.cxx index 31ed720e66335..54fb1354ad60c 100644 --- a/Detectors/CPV/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/CPV/workflow/src/EntropyEncoderSpec.cxx @@ -26,7 +26,7 @@ namespace o2 namespace cpv { -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR) { mTimer.Stop(); mTimer.Reset(); @@ -70,12 +70,14 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("triggers", "CPV", "CLUSTERTRIGRECS", 0, Lifetime::Timeframe); inputs.emplace_back("clusters", "CPV", "CLUSTERS", 0, Lifetime::Timeframe); - inputs.emplace_back("ctfdict", "CPV", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("CPV/Calib/CTFDictionaryTree")); + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "CPV", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("CPV/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -84,9 +86,8 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR) inputs, Outputs{{"CPV", "CTFDATA", 0, Lifetime::Timeframe}, {{"ctfrep"}, "CPV", "CTFENCREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; diff --git a/Detectors/CPV/workflow/src/entropy-encoder-workflow.cxx b/Detectors/CPV/workflow/src/entropy-encoder-workflow.cxx index d7e79c4cea430..90fedb1d5eb83 100644 --- a/Detectors/CPV/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/CPV/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "none", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -37,6 +38,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::cpv::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"))); + wf.emplace_back(o2::cpv::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/CTF/test/test_ctf_io_cpv.cxx b/Detectors/CTF/test/test_ctf_io_cpv.cxx index e4b91569d1df3..34a383a6875a0 100644 --- a/Detectors/CTF/test/test_ctf_io_cpv.cxx +++ b/Detectors/CTF/test/test_ctf_io_cpv.cxx @@ -28,6 +28,7 @@ #include #include #include +#include #include using namespace o2::cpv; diff --git a/Detectors/CTF/test/test_ctf_io_itsmft.cxx b/Detectors/CTF/test/test_ctf_io_itsmft.cxx index 13cbdf7745961..7f2ff8ce9f340 100644 --- a/Detectors/CTF/test/test_ctf_io_itsmft.cxx +++ b/Detectors/CTF/test/test_ctf_io_itsmft.cxx @@ -81,7 +81,7 @@ BOOST_DATA_TEST_CASE(CompressedClustersTest, boost_data::make(ANSVersions), ansV sw.Start(); std::vector vec; { - CTFCoder coder(o2::ctf::CTFCoderBase::OpType::Encoder, o2::detectors::DetID::ITS); + CTFCoder coder(o2::ctf::CTFCoderBase::OpType::Encoder, false); coder.setANSVersion(ansVersion); coder.encode(vec, rofRecVec, cclusVec, pattVec, pattIdConverter, 0); // compress } @@ -120,7 +120,7 @@ BOOST_DATA_TEST_CASE(CompressedClustersTest, boost_data::make(ANSVersions), ansV sw.Start(); const auto ctfImage = o2::itsmft::CTF::getImage(vec.data()); { - CTFCoder coder(o2::ctf::CTFCoderBase::OpType::Decoder, o2::detectors::DetID::ITS); + CTFCoder coder(o2::ctf::CTFCoderBase::OpType::Decoder, false); coder.decode(ctfImage, rofRecVecD, cclusVecD, pattVecD, nullptr, clPattLookup); // decompress } sw.Stop(); diff --git a/Detectors/CTF/workflow/include/CTFWorkflow/CTFReaderSpec.h b/Detectors/CTF/workflow/include/CTFWorkflow/CTFReaderSpec.h index b202013a6eea1..51f2fca2c8303 100644 --- a/Detectors/CTF/workflow/include/CTFWorkflow/CTFReaderSpec.h +++ b/Detectors/CTF/workflow/include/CTFWorkflow/CTFReaderSpec.h @@ -27,12 +27,15 @@ struct CTFReaderInp { std::string inpdata{}; o2::detectors::DetID::mask_t detMask = o2::detectors::DetID::FullMask; std::string copyCmd{}; + std::string copyDir{}; std::string tffileRegex{}; std::string remoteRegex{}; std::string metricChannel{}; std::string fileIRFrames{}; std::string fileRunTimeSpans{}; + std::string dictOpt{}; std::vector ctfIDs{}; + bool reverseCTFIDs{false}; bool skipSkimmedOutTF = false; bool invertIRFramesSelection = false; bool allowMissingDetectors = false; @@ -47,6 +50,9 @@ struct CTFReaderInp { unsigned int decSSpecEMC = 0; int tfRateLimit = -999; size_t minSHM = 0; + bool shuffle{false}; + bool doITSStaggering = false; + bool doMFTStaggering = false; }; /// create a processor spec diff --git a/Detectors/CTF/workflow/include/CTFWorkflow/CTFWriterSpec.h b/Detectors/CTF/workflow/include/CTFWorkflow/CTFWriterSpec.h index 5eb6d65e26cec..12ad483d90881 100644 --- a/Detectors/CTF/workflow/include/CTFWorkflow/CTFWriterSpec.h +++ b/Detectors/CTF/workflow/include/CTFWorkflow/CTFWriterSpec.h @@ -15,16 +15,23 @@ #define O2_CTFWRITER_SPEC #include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" #include "DetectorsCommonDataFormats/DetID.h" namespace o2 { namespace ctf { +struct CTFWriterInp { + o2::detectors::DetID::mask_t detMask = o2::detectors::DetID::FullMask; + int verbosity = 0; + int reportInterval = 200; + std::string outType = ""; + bool doITSStaggering = false; + bool doMFTStaggering = false; +}; /// create a processor spec -framework::DataProcessorSpec getCTFWriterSpec(o2::detectors::DetID::mask_t dets, const std::string& outType, int verbosity, int reportInterval); +framework::DataProcessorSpec getCTFWriterSpec(const o2::ctf::CTFWriterInp& inp); } // namespace ctf } // namespace o2 diff --git a/Detectors/CTF/workflow/src/CTFReaderSpec.cxx b/Detectors/CTF/workflow/src/CTFReaderSpec.cxx index aadc059ecd4fa..9fba8a220be55 100644 --- a/Detectors/CTF/workflow/src/CTFReaderSpec.cxx +++ b/Detectors/CTF/workflow/src/CTFReaderSpec.cxx @@ -11,9 +11,14 @@ /// @file CTFReaderSpec.cxx +#include #include +#include +#include + #include #include +#include #include "Framework/Logger.h" #include "Framework/ControlService.h" @@ -30,6 +35,7 @@ #include "CommonUtils/NameConf.h" #include "DetectorsCommonDataFormats/CTFHeader.h" #include "Headers/STFHeader.h" +#include "DataFormatsITSMFT/DPLAlpideParam.h" #include "DataFormatsITSMFT/CTF.h" #include "DataFormatsTPC/CTF.h" #include "DataFormatsTRD/CTF.h" @@ -49,7 +55,6 @@ #include "CCDB/BasicCCDBManager.h" #include "CommonConstants/LHCConstants.h" #include "Algorithm/RangeTokenizer.h" -#include #include using namespace o2::framework; @@ -108,7 +113,7 @@ class CTFReaderSpec : public o2::framework::Task int mCTFCounterAcc = 0; int mNFailedFiles = 0; int mFilesRead = 0; - int mTFLength = 128; + int mTFLength = 32; int mNWaits = 0; int mRunNumberPrev = -1; long mTotalWaitTime = 0; @@ -155,6 +160,9 @@ void CTFReaderSpec::stopReader() void CTFReaderSpec::init(InitContext& ic) { mInput.ctfIDs = o2::RangeTokenizer::tokenize(ic.options().get("select-ctf-ids")); + if ((mInput.reverseCTFIDs = ic.options().get("reverse-select-ctf-ids"))) { + std::reverse(mInput.ctfIDs.begin(), mInput.ctfIDs.end()); + } mUseLocalTFCounter = ic.options().get("local-tf-counter"); mImposeRunStartMS = ic.options().get("impose-run-start-timstamp"); mInput.checkTFLimitBeforeReading = ic.options().get("limit-tf-before-reading"); @@ -163,7 +171,7 @@ void CTFReaderSpec::init(InitContext& ic) mInput.maxTFsPerFile = ic.options().get("max-tf-per-file"); mInput.maxTFsPerFile = mInput.maxTFsPerFile > 0 ? mInput.maxTFsPerFile : 0x7fffffff; mRunning = true; - mFileFetcher = std::make_unique(mInput.inpdata, mInput.tffileRegex, mInput.remoteRegex, mInput.copyCmd); + mFileFetcher = std::make_unique(mInput.inpdata, mInput.tffileRegex, mInput.remoteRegex, mInput.copyCmd, mInput.copyDir); mFileFetcher->setMaxFilesInQueue(mInput.maxFileCache); mFileFetcher->setMaxLoops(mInput.maxLoops); mFileFetcher->setFailThreshold(ic.options().get("fetch-failure-threshold")); @@ -181,6 +189,48 @@ void CTFReaderSpec::init(InitContext& ic) } } +///_______________________________________ +template <> +void CTFReaderSpec::processDetector(DetID det, const CTFHeader& ctfHeader, ProcessingContext& pc) const +{ + if (mInput.detMask[det]) { + std::string lbl = det.getName(); + int nLayers = 1; + if (det == DetID::ITS) { + nLayers = mInput.doITSStaggering ? o2::itsmft::DPLAlpideParam::getNLayers() : 1; + } else if (det == DetID::MFT) { + nLayers = mInput.doMFTStaggering ? o2::itsmft::DPLAlpideParam::getNLayers() : 1; + } else { + LOGP(fatal, "This specialization is define only for ITS and MFT detectors, {} provided", det.getName()); + } + for (int iLayer = 0; iLayer < nLayers; iLayer++) { + auto& bufVec = pc.outputs().make>({lbl, mInput.subspec * 100 + iLayer}, ctfHeader.detectors[det] ? sizeof(o2::itsmft::CTF) : 0); + if (ctfHeader.detectors[det]) { + auto brName = nLayers == 1 ? lbl : fmt::format("{}_{}", lbl, iLayer); + o2::itsmft::CTF::readFromTree(bufVec, *(mCTFTree.get()), brName, mCurrTreeEntry); + } else if (!mInput.allowMissingDetectors) { + throw std::runtime_error(fmt::format("Requested detector {} is missing in the CTF", lbl)); + } + } + } +} + +///_______________________________________ +template +void CTFReaderSpec::processDetector(DetID det, const CTFHeader& ctfHeader, ProcessingContext& pc) const +{ + if (mInput.detMask[det]) { + const auto lbl = det.getName(); + auto& bufVec = pc.outputs().make>({lbl, mInput.subspec}, ctfHeader.detectors[det] ? sizeof(C) : 0); + if (ctfHeader.detectors[det]) { + C::readFromTree(bufVec, *(mCTFTree.get()), lbl, mCurrTreeEntry); + } else if (!mInput.allowMissingDetectors) { + throw std::runtime_error(fmt::format("Requested detector {} is missing in the CTF", lbl)); + } + // setMessageHeader(pc, ctfHeader, lbl); + } +} + void CTFReaderSpec::runTimeRangesToIRFrameSelector(const o2::framework::TimingInfo& timingInfo) { // convert entries in the runTimeRanges to IRFrameSelector, if needed, convert time to orbit @@ -227,7 +277,7 @@ void CTFReaderSpec::loadRunTimeSpans(const std::string& flname) { std::ifstream inputFile(flname); if (!inputFile) { - LOGP(fatal, "Failed to open selected run/timespans file {}", mInput.fileRunTimeSpans); + LOGP(fatal, "Failed to open selected run/timespans file {}", flname); } std::string line; size_t cntl = 0, cntr = 0; @@ -279,7 +329,7 @@ void CTFReaderSpec::loadRunTimeSpans(const std::string& flname) logError(); } } - LOGP(info, "Read {} time-spans for {} runs from {}", cntr, mRunTimeRanges.size(), mInput.fileRunTimeSpans); + LOGP(info, "Read {} time-spans for {} runs from {}", cntr, mRunTimeRanges.size(), flname); inputFile.close(); } @@ -299,6 +349,27 @@ void CTFReaderSpec::openCTFFile(const std::string& flname) if (mCTFTree->GetEntries() < 1) { throw std::runtime_error(fmt::format("CTF tree in {} has 0 entries, skipping", flname)); } + if (mInput.shuffle) { + if (mInput.ctfIDs.empty()) { + int entries = mCTFTree->GetEntries(); + if (mInput.maxTFs > 0) { + entries = std::min(entries, mInput.maxTFs); + } + if (mInput.maxTFsPerFile > 0) { + entries = std::min(entries, mInput.maxTFsPerFile); + } + mInput.ctfIDs.clear(); + mInput.ctfIDs.resize(entries); + std::iota(mInput.ctfIDs.begin(), mInput.ctfIDs.end(), 0); + } + std::random_device dev; + std::mt19937 gen{dev()}; + std::shuffle(mInput.ctfIDs.begin(), mInput.ctfIDs.end(), gen); + LOGP(info, "will shuffle reading of CTF entries in this order:"); + for (int i{0}; i < (int)mInput.ctfIDs.size(); ++i) { + LOGP(info, "\tTF {:02} -> {:02}", i, mInput.ctfIDs[i]); + } + } } catch (const std::exception& e) { LOG(error) << "Cannot process " << flname << ", reason: " << e.what(); mCTFTree.reset(); @@ -322,9 +393,12 @@ void CTFReaderSpec::run(ProcessingContext& pc) long startWait = 0; while (mRunning) { - if (mCTFTree) { // there is a tree open with multiple CTF - if (mInput.ctfIDs.empty() || mInput.ctfIDs[mSelIDEntry] == mCTFCounter) { // no selection requested or matching CTF ID is found + if (mCTFTree) { // there is a tree open with multiple CTF + if (mInput.ctfIDs.empty() || mInput.ctfIDs[mSelIDEntry] == mCTFCounter || mInput.shuffle || mInput.reverseCTFIDs) { // no selection requested or matching CTF ID is found LOG(debug) << "TF " << mCTFCounter << " of " << mInput.maxTFs << " loop " << mFileFetcher->getNLoops(); + if (mInput.shuffle || mInput.reverseCTFIDs) { + mCurrTreeEntry = mInput.ctfIDs[mSelIDEntry]; + } mSelIDEntry++; if (processTF(pc)) { break; @@ -500,8 +574,13 @@ bool CTFReaderSpec::processTF(ProcessingContext& pc) ///_______________________________________ void CTFReaderSpec::checkTreeEntries() { - // check if the tree has entries left, if needed, close current tree/file - if (++mCurrTreeEntry >= mCTFTree->GetEntries() || (mInput.maxTFsPerFile > 0 && mCurrTreeEntry >= mInput.maxTFsPerFile)) { // this file is done, check if there are other files + bool reachedEnd{false}; + if (mInput.shuffle || mInput.reverseCTFIDs) { // last entry is last id + reachedEnd = (mCurrTreeEntry == mInput.ctfIDs.back()); + } else { // check if the tree has entries left, if needed, close current tree/file + reachedEnd = (++mCurrTreeEntry >= mCTFTree->GetEntries()); + } + if (reachedEnd || (mInput.maxTFsPerFile > 0 && mCurrTreeEntry >= mInput.maxTFsPerFile)) { // this file is done, check if there are other files mCTFTree.reset(); mCTFFile->Close(); mCTFFile.reset(); @@ -526,22 +605,6 @@ void CTFReaderSpec::setMessageHeader(ProcessingContext& pc, const CTFHeader& ctf dph->creation = ctfHeader.creationTime; } -///_______________________________________ -template -void CTFReaderSpec::processDetector(DetID det, const CTFHeader& ctfHeader, ProcessingContext& pc) const -{ - if (mInput.detMask[det]) { - const auto lbl = det.getName(); - auto& bufVec = pc.outputs().make>({lbl, mInput.subspec}, ctfHeader.detectors[det] ? sizeof(C) : 0); - if (ctfHeader.detectors[det]) { - C::readFromTree(bufVec, *(mCTFTree.get()), lbl, mCurrTreeEntry); - } else if (!mInput.allowMissingDetectors) { - throw std::runtime_error(fmt::format("Requested detector {} is missing in the CTF", lbl)); - } - // setMessageHeader(pc, ctfHeader, lbl); - } -} - ///_______________________________________ void CTFReaderSpec::tryToFixCTFHeader(CTFHeader& ctfHeader) const { @@ -600,7 +663,19 @@ DataProcessorSpec getCTFReaderSpec(const CTFReaderInp& inp) for (auto id = DetID::First; id <= DetID::Last; id++) { if (inp.detMask[id]) { DetID det(id); - outputs.emplace_back(OutputLabel{det.getName()}, det.getDataOrigin(), "CTFDATA", inp.subspec, Lifetime::Timeframe); + if (det == DetID::ITS) { + uint32_t nLayers = inp.doITSStaggering ? o2::itsmft::DPLAlpideParam::getNLayers() : 1; + for (uint32_t iLayer = 0; iLayer < nLayers; iLayer++) { + outputs.emplace_back(OutputLabel{det.getName()}, det.getDataOrigin(), "CTFDATA", inp.subspec * 100 + iLayer, Lifetime::Timeframe); + } + } else if (det == DetID::MFT) { + uint32_t nLayers = inp.doMFTStaggering ? o2::itsmft::DPLAlpideParam::getNLayers() : 1; + for (uint32_t iLayer = 0; iLayer < nLayers; iLayer++) { + outputs.emplace_back(OutputLabel{det.getName()}, det.getDataOrigin(), "CTFDATA", inp.subspec * 100 + iLayer, Lifetime::Timeframe); + } + } else { + outputs.emplace_back(OutputLabel{det.getName()}, det.getDataOrigin(), "CTFDATA", inp.subspec, Lifetime::Timeframe); + } } } if (!inp.fileIRFrames.empty() || !inp.fileRunTimeSpans.empty()) { @@ -609,8 +684,8 @@ DataProcessorSpec getCTFReaderSpec(const CTFReaderInp& inp) if (!inp.sup0xccdb) { outputs.emplace_back(OutputSpec{{"TFDist"}, o2::header::gDataOriginFLP, o2::header::gDataDescriptionDISTSTF, 0xccdb}); } - options.emplace_back(ConfigParamSpec{"select-ctf-ids", VariantType::String, "", {"comma-separated list CTF IDs to inject (from cumulative counter of CTFs seen)"}}); + options.emplace_back(ConfigParamSpec{"reverse-select-ctf-ids", VariantType::Bool, false, {"reverse order of to inject CTF IDs"}}); options.emplace_back(ConfigParamSpec{"impose-run-start-timstamp", VariantType::Int64, 0L, {"impose run start time stamp (ms), ignored if 0"}}); options.emplace_back(ConfigParamSpec{"local-tf-counter", VariantType::Bool, false, {"reassign header.tfCounter from local TF counter"}}); options.emplace_back(ConfigParamSpec{"fetch-failure-threshold", VariantType::Float, 0.f, {"Fail if too many failures( >0: fraction, <0: abs number, 0: no threshold)"}}); diff --git a/Detectors/CTF/workflow/src/CTFWriterSpec.cxx b/Detectors/CTF/workflow/src/CTFWriterSpec.cxx index ba4542969a712..f175bf4c2e5d3 100644 --- a/Detectors/CTF/workflow/src/CTFWriterSpec.cxx +++ b/Detectors/CTF/workflow/src/CTFWriterSpec.cxx @@ -12,11 +12,10 @@ /// @file CTFWriterSpec.cxx #include "Framework/Logger.h" -#include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/InputSpec.h" +#include "Framework/Task.h" #include "Framework/RawDeviceService.h" -#include "Framework/CommonServices.h" #include "Framework/DataTakingContext.h" #include "Framework/TimingInfo.h" #include @@ -29,6 +28,7 @@ #include "DetectorsCommonDataFormats/EncodedBlocks.h" #include "DetectorsCommonDataFormats/FileMetaData.h" #include "CommonUtils/StringUtils.h" +#include "DataFormatsITSMFT/DPLAlpideParam.h" #include "DataFormatsITSMFT/CTF.h" #include "DataFormatsTPC/CTF.h" #include "DataFormatsTRD/CTF.h" @@ -94,17 +94,19 @@ size_t appendToTree(TTree& tree, const std::string brname, T& ptr) using DetID = o2::detectors::DetID; using FTrans = o2::rans::DenseHistogram; -class CTFWriterSpec : public o2::framework::Task +class CTFWriterSpec final : public o2::framework::Task { public: CTFWriterSpec() = delete; - CTFWriterSpec(DetID::mask_t dm, const std::string& outType, int verbosity, int reportInterval); + CTFWriterSpec(const o2::ctf::CTFWriterInp&); ~CTFWriterSpec() final { finalize(); } void init(o2::framework::InitContext& ic) final; void run(o2::framework::ProcessingContext& pc) final; void endOfStream(o2::framework::EndOfStreamContext& ec) final { finalize(); } void stop() final { finalize(); } - bool isPresent(DetID id) const { return mDets[id]; } + bool isPresent(DetID id) const { return mInput.detMask[id]; } + + static std::string getBinding(const std::string& name, int spec) { return fmt::format("{}_{}", name, spec); } private: void updateTimeDependentParams(ProcessingContext& pc); @@ -121,7 +123,7 @@ class CTFWriterSpec : public o2::framework::Task void removeLockFile(); void finalize(); - DetID::mask_t mDets; // detectors + CTFWriterInp mInput; bool mFinalized = false; bool mWriteCTF = true; bool mCreateDict = false; @@ -130,8 +132,6 @@ class CTFWriterSpec : public o2::framework::Task bool mRejectCurrentTF = false; bool mFallBackDirUsed = false; bool mFallBackDirProvided = false; - int mReportInterval = -1; - int mVerbosity = 0; int mSaveDictAfter = 0; // if positive and mWriteCTF==true, save dictionary after each mSaveDictAfter TFs processed uint32_t mPrevDictTimeStamp = 0; // timestamp of the previously stored dictionary uint32_t mDictTimeStamp = 0; // timestamp of the currently stored dictionary @@ -155,7 +155,6 @@ class CTFWriterSpec : public o2::framework::Task std::vector mTFOrbits{}; // 1st orbits of TF accumulated in current file o2::framework::DataTakingContext mDataTakingContext{}; o2::framework::TimingInfo mTimingInfo{}; - std::string mOutputType{}; // RS FIXME once global/local options clash is solved, --output-type will become device option std::string mDictDir{}; std::string mCTFDir{}; std::string mHostName{}; @@ -190,8 +189,8 @@ class CTFWriterSpec : public o2::framework::Task const std::string CTFWriterSpec::TMPFileEnding{".part"}; //___________________________________________________________________ -CTFWriterSpec::CTFWriterSpec(DetID::mask_t dm, const std::string& outType, int verbosity, int reportInterval) - : mDets(dm), mOutputType(outType), mReportInterval(reportInterval), mVerbosity(verbosity) +CTFWriterSpec::CTFWriterSpec(const o2::ctf::CTFWriterInp& inp) + : mInput(inp) { std::for_each(mIsSaturatedFrequencyTable.begin(), mIsSaturatedFrequencyTable.end(), [](auto& bitset) { bitset.reset(); }); mTimer.Stop(); @@ -202,7 +201,7 @@ CTFWriterSpec::CTFWriterSpec(DetID::mask_t dm, const std::string& outType, int v void CTFWriterSpec::init(InitContext& ic) { // auto outmode = ic.options().get("output-type"); // RS FIXME once global/local options clash is solved, --output-type will become device option - auto outmode = mOutputType; + auto outmode = mInput.outType; if (outmode == "ctf") { mWriteCTF = true; mCreateDict = false; @@ -301,71 +300,82 @@ size_t CTFWriterSpec::processDet(o2::framework::ProcessingContext& pc, DetID det { static bool warnedEmpty = false; size_t sz = 0; - if (!isPresent(det) || !pc.inputs().isValid(det.getName())) { + + if (!isPresent(det) || !pc.inputs().isValid(getBinding(det.getName(), 0))) { mSizeReport += fmt::format(" {}:N/A", det.getName()); return sz; } - auto ctfBuffer = pc.inputs().get>(det.getName()); - const o2::ctf::BufferType* bdata = ctfBuffer.data(); - if (bdata) { - if (warnedEmpty) { - throw std::runtime_error(fmt::format("Non-empty input was seen at {}-th TF after empty one for {}, this will lead to misalignment of detectors in CTF", mNCTF, det.getName())); - } - const auto ctfImage = C::getImage(bdata); - ctfImage.print(o2::utils::Str::concat_string(det.getName(), ": "), mVerbosity); - if (mWriteCTF && !mRejectCurrentTF) { - sz = ctfImage.appendToTree(*tree, det.getName()); - header.detectors.set(det); - } else { - sz = ctfBuffer.size(); - } - if (mCreateDict) { - if (mFreqsAccumulation[det].empty()) { - mFreqsAccumulation[det].resize(C::getNBlocks()); - mFreqsMetaData[det].resize(C::getNBlocks()); + + uint32_t nLayers = 1; + if (det == DetID::ITS) { + nLayers = mInput.doITSStaggering ? o2::itsmft::DPLAlpideParam::getNLayers() : 1; + } else if (det == DetID::MFT) { + nLayers = mInput.doMFTStaggering ? o2::itsmft::DPLAlpideParam::getNLayers() : 1; + } + for (uint32_t iLayer = 0; iLayer < nLayers; iLayer++) { + auto binding = getBinding(det.getName(), iLayer); + auto ctfBuffer = pc.inputs().get>(binding); + const o2::ctf::BufferType* bdata = ctfBuffer.data(); + if (bdata) { + if (warnedEmpty) { + throw std::runtime_error(fmt::format("Non-empty input was seen at {}-th TF after empty one for {}, this will lead to misalignment of detectors in CTF", mNCTF, det.getName())); } - if (!mHeaders[det]) { // store 1st header - mHeaders[det] = ctfImage.cloneHeader(); - auto& hb = *static_cast(mHeaders[det].get()); - hb.det = det; + const auto ctfImage = C::getImage(bdata); + ctfImage.print(o2::utils::Str::concat_string(binding, ": "), mInput.verbosity); + if (mWriteCTF && !mRejectCurrentTF) { + sz += ctfImage.appendToTree(*tree, nLayers > 1 ? binding : det.getName()); + header.detectors.set(det); + } else { + sz += ctfBuffer.size(); } - for (int ib = 0; ib < C::getNBlocks(); ib++) { - if (!mIsSaturatedFrequencyTable[det][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); - if ([&, this]() { - try { - freq.addFrequencies(bl.getDict(), bl.getDict() + bl.getNDict(), md.min); - } catch (const std::overflow_error& e) { - LOGP(warning, "unable to add frequency table for {}, block {} due to overflow", det.getName(), ib); - mIsSaturatedFrequencyTable[det][ib] = true; - return false; - } - return true; - }()) { - auto newProbBits = static_cast(o2::rans::compat::computeRenormingPrecision(countNUsedAlphabetSymbols(freq))); - auto histogramView = o2::rans::trim(o2::rans::makeHistogramView(freq)); - mdSave = ctf::detail::makeMetadataRansDict(newProbBits, - static_cast(histogramView.getMin()), - static_cast(histogramView.getMax()), - static_cast(histogramView.size()), - md.opt); - mFreqsAccumulation[det][ib] = std::move(freq); + if (mCreateDict) { // RSTODO + if (mFreqsAccumulation[det].empty()) { + mFreqsAccumulation[det].resize(C::getNBlocks()); + mFreqsMetaData[det].resize(C::getNBlocks()); + } + if (!mHeaders[det]) { // store 1st header + mHeaders[det] = ctfImage.cloneHeader(); + auto& hb = *static_cast(mHeaders[det].get()); + hb.det = det; + } + for (int ib = 0; ib < C::getNBlocks(); ib++) { + if (!mIsSaturatedFrequencyTable[det][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); + if ([&, this]() { + try { + freq.addFrequencies(bl.getDict(), bl.getDict() + bl.getNDict(), md.min); + } catch (const std::overflow_error& e) { + LOGP(warning, "unable to add frequency table for {}, block {} due to overflow", det.getName(), ib); + mIsSaturatedFrequencyTable[det][ib] = true; + return false; + } + return true; + }()) { + auto newProbBits = static_cast(o2::rans::compat::computeRenormingPrecision(countNUsedAlphabetSymbols(freq))); + auto histogramView = o2::rans::trim(o2::rans::makeHistogramView(freq)); + mdSave = ctf::detail::makeMetadataRansDict(newProbBits, + static_cast(histogramView.getMin()), + static_cast(histogramView.getMax()), + static_cast(histogramView.size()), + md.opt); + mFreqsAccumulation[det][ib] = std::move(freq); + } } } } } - } - } else { - if (!warnedEmpty) { - if (mNCTF) { - throw std::runtime_error(fmt::format("Empty input was seen at {}-th TF after non-empty one for {}, this will lead to misalignment of detectors in CTF", mNCTF, det.getName())); + } else { + if (!warnedEmpty) { + if (mNCTF) { + throw std::runtime_error(fmt::format("Empty input was seen at {}-th TF after non-empty one for {}, this will lead to misalignment of detectors in CTF", mNCTF, det.getName())); + } + LOGP(important, "Empty CTF provided for {}, skipping and will not report anymore", det.getName()); + warnedEmpty = true; } - LOGP(important, "Empty CTF provided for {}, skipping and will not report anymore", det.getName()); - warnedEmpty = true; } } mSizeReport += fmt::format(" {}:{}", det.getName(), fmt::group_digits(sz)); @@ -417,10 +427,19 @@ 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; + uint32_t nLayers = 1; + if (det == DetID::ITS) { + nLayers = mInput.doITSStaggering ? o2::itsmft::DPLAlpideParam::getNLayers() : 1; + } else if (det == DetID::MFT) { + nLayers = mInput.doMFTStaggering ? o2::itsmft::DPLAlpideParam::getNLayers() : 1; + } + for (uint32_t iLayer = 0; iLayer < nLayers; iLayer++) { + auto binding = getBinding(det.getName(), iLayer); + if (!isPresent(det) || !pc.inputs().isValid(binding)) { + continue; + } + s += pc.inputs().get>(binding).size(); } - s += pc.inputs().get>(det.getName()).size(); } return s; } @@ -496,7 +515,7 @@ void CTFWriterSpec::run(ProcessingContext& pc) szCTFperDet[DetID::FDD] = processDet(pc, DetID::FDD, header, mCTFTreeOut.get()); szCTFperDet[DetID::CTP] = processDet(pc, DetID::CTP, header, mCTFTreeOut.get()); szCTF = std::accumulate(szCTFperDet.begin(), szCTFperDet.end(), 0); - if (mReportInterval > 0 && (mTimingInfo.tfCounter % mReportInterval) == 0) { + if (mInput.reportInterval > 0 && (mTimingInfo.tfCounter % mInput.reportInterval) == 0) { LOGP(important, "CTF {} size report:{} - Total:{}", mTimingInfo.tfCounter, mSizeReport, fmt::group_digits(szCTF)); } @@ -660,7 +679,7 @@ void CTFWriterSpec::storeDictionaries() // monolitic dictionary in tree format mDictTimeStamp = uint32_t(std::time(nullptr)); auto getFileName = [this](bool curr) { - return fmt::format("{}{}Tree_{}_{}_{}.root", this->mDictDir, o2::base::NameConf::CTFDICT, DetID::getNames(this->mDets, '-'), curr ? this->mDictTimeStamp : this->mPrevDictTimeStamp, curr ? this->mNCTF : this->mNCTFPrevDict); + return fmt::format("{}{}Tree_{}_{}_{}.root", this->mDictDir, o2::base::NameConf::CTFDICT, DetID::getNames(this->mInput.detMask, '-'), curr ? this->mDictTimeStamp : this->mPrevDictTimeStamp, curr ? this->mNCTF : this->mNCTFPrevDict); }; auto dictFileName = getFileName(true); mDictFileOut.reset(TFile::Open(dictFileName.c_str(), "recreate")); @@ -788,13 +807,22 @@ size_t CTFWriterSpec::getAvailableDiskSpace(const std::string& path, int level) } //___________________________________________________________________ -DataProcessorSpec getCTFWriterSpec(DetID::mask_t dets, const std::string& outType, int verbosity, int reportInterval) +DataProcessorSpec getCTFWriterSpec(const o2::ctf::CTFWriterInp& inp) { std::vector inputs; 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); + if (inp.detMask[id]) { + uint32_t nLayers = 1; + DetID det{id}; + if (det == DetID::ITS) { + nLayers = inp.doITSStaggering ? o2::itsmft::DPLAlpideParam::getNLayers() : 1; + } else if (det == DetID::MFT) { + nLayers = inp.doMFTStaggering ? o2::itsmft::DPLAlpideParam::getNLayers() : 1; + } + for (uint32_t iLayer = 0; iLayer < nLayers; iLayer++) { + inputs.emplace_back(CTFWriterSpec::getBinding(det.getName(), iLayer), det.getDataOrigin(), "CTFDATA", iLayer, Lifetime::Timeframe); + } LOG(debug) << "Det " << DetID::getName(id) << " added"; } } @@ -803,24 +831,25 @@ DataProcessorSpec getCTFWriterSpec(DetID::mask_t dets, const std::string& outTyp inputs, Outputs{{OutputLabel{"ctfdone"}, "CTF", "DONE", 0, Lifetime::Timeframe}, {"CTF", "SIZES", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(dets, outType, verbosity, reportInterval)}, // 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::Int64, 0ll, {"autosave CTF tree with multiple CTFs after every N CTFs if >0 or every -N MBytes if < 0"}}, - {"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"}}, - {"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)"}}, - {"md5-for-meta", VariantType::Bool, false, {"fill CTF file MD5 sum in the metadata file"}}, - {"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"}}, - {"ctf-rejection", VariantType::Int, 0, {">0: percentage to reject randomly, <0: reject if timeslice%|value|!=0"}}, - {"ctf-file-compression", VariantType::Int, 0, {"if >= 0: impose CTF file compression level"}}, - {"require-free-disk", VariantType::Float, 0.f, {"pause writing op. if available disk space is below this margin, in bytes if >0, as a fraction of total if <0"}}, - {"wait-for-free-disk", VariantType::Float, 10.f, {"if paused due to the low disk space, recheck after this time (in s)"}}, - {"max-wait-for-free-disk", VariantType::Float, 60.f, {"produce fatal if paused due to the low disk space for more than this amount in s."}}, - {"ignore-partition-run-dir", VariantType::Bool, false, {"Do not creare partition-run directory in output-dir"}}}}; + AlgorithmSpec{adaptFromTask(inp)}, + Options{ + //{"output-type", VariantType::String, "ctf", {"output types: ctf (per TF) or dict (create dictionaries) or both or none"}}, + {"save-ctf-after", VariantType::Int64, 0ll, {"autosave CTF tree with multiple CTFs after every N CTFs if >0 or every -N MBytes if < 0"}}, + {"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"}}, + {"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)"}}, + {"md5-for-meta", VariantType::Bool, false, {"fill CTF file MD5 sum in the metadata file"}}, + {"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"}}, + {"ctf-rejection", VariantType::Int, 0, {">0: percentage to reject randomly, <0: reject if timeslice%|value|!=0"}}, + {"ctf-file-compression", VariantType::Int, 0, {"if >= 0: impose CTF file compression level"}}, + {"require-free-disk", VariantType::Float, 0.f, {"pause writing op. if available disk space is below this margin, in bytes if >0, as a fraction of total if <0"}}, + {"wait-for-free-disk", VariantType::Float, 10.f, {"if paused due to the low disk space, recheck after this time (in s)"}}, + {"max-wait-for-free-disk", VariantType::Float, 60.f, {"produce fatal if paused due to the low disk space for more than this amount in s."}}, + {"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 1f0ef9a3b871b..366fa76f74983 100644 --- a/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx +++ b/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx @@ -25,6 +25,7 @@ // Specific detectors specs #include "ITSMFTWorkflow/EntropyDecoderSpec.h" +#include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" #include "TPCWorkflow/EntropyDecoderSpec.h" #include "TRDWorkflow/EntropyDecoderSpec.h" #include "HMPIDWorkflow/EntropyDecoderSpec.h" @@ -52,11 +53,14 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options; options.push_back(ConfigParamSpec{"ctf-input", VariantType::String, "none", {"comma-separated list CTF input files"}}); + options.push_back(ConfigParamSpec{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}); 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{"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{"shuffle", VariantType::Bool, false, {"shuffle TF sending order (for debug)"}}); options.push_back(ConfigParamSpec{"copy-cmd", VariantType::String, "alien_cp ?src file://?dst", {"copy command for remote files or no-copy to avoid copying"}}); // Use "XrdSecPROTOCOL=sss,unix xrdcp -N root://eosaliceo2.cern.ch/?src ?dst" for direct EOS access + options.push_back(ConfigParamSpec{"copy-dir", VariantType::String, "/tmp/", {"copy base directory for remote files"}}); 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, "^(alien://|)/alice/data/.+", {"regex string to identify remote files"}}); // Use "^/eos/aliceo2/.+" for direct EOS access options.push_back(ConfigParamSpec{"max-cached-files", VariantType::Int, 3, {"max CTF files queued (copied for remote source)"}}); @@ -78,6 +82,7 @@ void customize(std::vector& workflowOptions) options.push_back(ConfigParamSpec{"timeframes-shm-limit", VariantType::String, "0", {"Minimum amount of SHM required in order to publish data"}}); options.push_back(ConfigParamSpec{"metric-feedback-channel-format", VariantType::String, "name=metric-feedback,type=pull,method=connect,address=ipc://{}metric-feedback-{},transport=shmem,rateLogging=0", {"format for the metric-feedback channel for TF rate limiting"}}); options.push_back(ConfigParamSpec{"combine-devices", VariantType::Bool, false, {"combine multiple DPL devices (entropy decoders)"}}); + o2::itsmft::DPLAlpideParamInitializer::addConfigOption(options); std::swap(workflowOptions, options); } @@ -120,7 +125,9 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) ctfInput.maxFileCache = std::max(1, configcontext.options().get("max-cached-files")); + ctfInput.shuffle = configcontext.options().get("shuffle"); ctfInput.copyCmd = configcontext.options().get("copy-cmd"); + ctfInput.copyDir = configcontext.options().get("copy-dir"); ctfInput.tffileRegex = configcontext.options().get("ctf-file-regex"); ctfInput.remoteRegex = configcontext.options().get("remote-regex"); ctfInput.allowMissingDetectors = configcontext.options().get("allow-missing-detectors"); @@ -130,6 +137,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) ctfInput.fileRunTimeSpans = configcontext.options().get("run-time-span-file"); ctfInput.skipSkimmedOutTF = configcontext.options().get("skip-skimmed-out-tf"); ctfInput.invertIRFramesSelection = configcontext.options().get("invert-irframe-selection"); + ctfInput.dictOpt = configcontext.options().get("ctf-dict"); int verbosity = configcontext.options().get("ctf-reader-verbosity"); int rateLimitingIPCID = std::stoi(configcontext.options().get("timeframes-rate-limit-ipcid")); @@ -143,6 +151,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) if (!ctfInput.fileIRFrames.empty() && !ctfInput.fileRunTimeSpans.empty()) { LOGP(fatal, "One cannot provide --ir-frames-files and --run-time-span-file options simultaneously"); } + ctfInput.doITSStaggering = o2::itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(configcontext); + ctfInput.doMFTStaggering = o2::itsmft::DPLAlpideParamInitializer::isMFTStaggeringEnabled(configcontext); specs.push_back(o2::ctf::getCTFReaderSpec(ctfInput)); @@ -179,52 +189,54 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) // add decoders for all allowed detectors. if (ctfInput.detMask[DetID::ITS]) { - addSpecs(o2::itsmft::getEntropyDecoderSpec(DetID::getDataOrigin(DetID::ITS), verbosity, configcontext.options().get("its-digits"), ctfInput.subspec)); + bool doStag = o2::itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(configcontext); + addSpecs(o2::itsmft::getITSEntropyDecoderSpec(verbosity, doStag, configcontext.options().get("its-digits"), ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::MFT]) { - addSpecs(o2::itsmft::getEntropyDecoderSpec(DetID::getDataOrigin(DetID::MFT), verbosity, configcontext.options().get("mft-digits"), ctfInput.subspec)); + bool doStag = o2::itsmft::DPLAlpideParamInitializer::isMFTStaggeringEnabled(configcontext); + addSpecs(o2::itsmft::getMFTEntropyDecoderSpec(verbosity, doStag, configcontext.options().get("mft-digits"), ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::TPC]) { - addSpecs(o2::tpc::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::tpc::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::TRD]) { - addSpecs(o2::trd::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::trd::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::TOF]) { - addSpecs(o2::tof::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::tof::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::FT0]) { - addSpecs(o2::ft0::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::ft0::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::FV0]) { - addSpecs(o2::fv0::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::fv0::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::FDD]) { - addSpecs(o2::fdd::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::fdd::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::MID]) { - addSpecs(o2::mid::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::mid::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::MCH]) { - addSpecs(o2::mch::getEntropyDecoderSpec(verbosity, "mch-entropy-decoder", ctfInput.subspec)); + addSpecs(o2::mch::getEntropyDecoderSpec(verbosity, "mch-entropy-decoder", ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::EMC]) { - addSpecs(o2::emcal::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.decSSpecEMC)); + addSpecs(o2::emcal::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.decSSpecEMC, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::PHS]) { - addSpecs(o2::phos::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::phos::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::CPV]) { - addSpecs(o2::cpv::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::cpv::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::ZDC]) { - addSpecs(o2::zdc::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::zdc::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::HMP]) { - addSpecs(o2::hmpid::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::hmpid::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::CTP]) { - addSpecs(o2::ctp::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::ctp::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } bool combine = configcontext.options().get("combine-devices"); diff --git a/Detectors/CTF/workflow/src/ctf-writer-workflow.cxx b/Detectors/CTF/workflow/src/ctf-writer-workflow.cxx index 2757192727521..77dbbd80bc1a7 100644 --- a/Detectors/CTF/workflow/src/ctf-writer-workflow.cxx +++ b/Detectors/CTF/workflow/src/ctf-writer-workflow.cxx @@ -20,6 +20,7 @@ #include "CTFWorkflow/CTFWriterSpec.h" #include "DetectorsCommonDataFormats/DetID.h" #include "CommonUtils/ConfigurableParam.h" +#include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" using namespace o2::framework; using DetID = o2::detectors::DetID; @@ -35,6 +36,7 @@ void customize(std::vector& workflowOptions) options.push_back(ConfigParamSpec{"ctf-writer-verbosity", VariantType::Int, 0, {"verbosity level (0: summary per detector, 1: summary per block"}}); options.push_back(ConfigParamSpec{"report-data-size-interval", VariantType::Int, 200, {"report sizes per detector for every N-th timeframe"}}); options.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}); + o2::itsmft::DPLAlpideParamInitializer::addConfigOption(options); std::swap(workflowOptions, options); } @@ -51,7 +53,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { DetID::mask_t dets = 0; o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); - std::string outType{}; // RS FIXME once global/local options clash is solved, --output-type will become device option + o2::ctf::CTFWriterInp inp; if (!configcontext.helpOnCommandLine()) { dets.set(); // by default read all auto mskOnly = DetID::getMask(configcontext.options().get("onlyDet")); @@ -64,10 +66,14 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) if (dets.none()) { throw std::invalid_argument("Invalid workflow: no detectors found"); } - outType = configcontext.options().get("output-type"); + inp.detMask = dets; + inp.outType = configcontext.options().get("output-type"); } - WorkflowSpec specs{o2::ctf::getCTFWriterSpec(dets, outType, - configcontext.options().get("ctf-writer-verbosity"), - configcontext.options().get("report-data-size-interval"))}; + inp.verbosity = configcontext.options().get("ctf-writer-verbosity"); + inp.reportInterval = configcontext.options().get("report-data-size-interval"); + inp.doITSStaggering = o2::itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(configcontext); + inp.doMFTStaggering = o2::itsmft::DPLAlpideParamInitializer::isMFTStaggeringEnabled(configcontext); + + WorkflowSpec specs{o2::ctf::getCTFWriterSpec(inp)}; return std::move(specs); } diff --git a/Detectors/CTP/macro/GetAndSave.C b/Detectors/CTP/macro/GetAndSave.C index 345bb1caf4a96..ff70a3055c957 100644 --- a/Detectors/CTP/macro/GetAndSave.C +++ b/Detectors/CTP/macro/GetAndSave.C @@ -44,7 +44,7 @@ void GetAndSave(std::string ccdbHost = "http://ccdb-test.cern.ch:8080") for (auto const& run : runs) { CTPConfiguration ctpcfg; CTPRunScalers scl; - map metadata; // can be empty + std::map metadata; // can be empty metadata["runNumber"] = run; CTPRunScalers* ctpscalers = mgr.getSpecific(CCDBPathCTPScalers, timestamps[i], metadata); if (ctpscalers == nullptr) { diff --git a/Detectors/CTP/macro/PlotPbLumi.C b/Detectors/CTP/macro/PlotPbLumi.C index 04666d5bd1cf6..4bda8d25e006e 100644 --- a/Detectors/CTP/macro/PlotPbLumi.C +++ b/Detectors/CTP/macro/PlotPbLumi.C @@ -9,10 +9,10 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file TestCTPScalers.C +/// \file PlotPbLumi.C /// \brief create CTP scalers, test it and add to database /// \author Roman Lietava -// root -b -q "GetScalers.C(\"519499\", 1656286373953)" +// root "PLotPbLumi.C(519499)" #if !defined(__CLING__) || defined(__ROOTCLING__) #include @@ -30,12 +30,21 @@ #include #endif using namespace o2::ctp; -void PlotPbLumi(int runNumber, int fillN, std::string ccdbHost = "http://ccdb-test.cern.ch:8080") +// +// sum = 0: TCE and TSC separatelly otherwise TCE and (TCE+TSC) +// qc = 0: takes scalers from CCDB (available only for finished runs) otherwise from QCCDB (available for active runs) +// t0-tlast: window in seconds counted from beginning of run +// +void PlotPbLumi(int runNumber = 567905, bool sum = 0, bool qc = 0, Double_t t0 = 0., Double_t tlast = 0.) { // - // what = 1: znc rate - // what = 2: (TCE+TSC)/ZNC - // what = 3: TCE/ZNC - std::string mCCDBPathCTPScalers = "CTP/Calib/Scalers"; + // PLots in one canvas + // znc rate/28 + // R = (TCE+TSC)*TVX*B*/ZNC*28 + // R = TCE*TVX*B/ZNC*28 + // R = VCH*TVX*B/ZNC*28 + std::string ccdbHost = "http://alice-ccdb.cern.ch"; + std::string mCCDBPathCTPScalers = "/CTP/Calib/Scalers"; + std::string mCCDBPathCTPScalersQC = "qc/CTP/Scalers"; std::string mCCDBPathCTPConfig = "CTP/Config/Config"; auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance(); // Timestamp @@ -43,20 +52,26 @@ void PlotPbLumi(int runNumber, int fillN, std::string ccdbHost = "http://ccdb-te uint64_t timeStamp = (soreor.second - soreor.first) / 2 + soreor.first; std::cout << "Timestamp:" << timeStamp << std::endl; // Filling - std::string sfill = std::to_string(fillN); - std::map metadata; - metadata["fillNumber"] = sfill; - auto lhcifdata = ccdbMgr.getSpecific("GLO/Config/GRPLHCIF", timeStamp, metadata); + auto lhcifdata = ccdbMgr.getForRun("GLO/Config/GRPLHCIF", runNumber); + // auto lhcifdata = ccdbMgr.getSpecific("GLO/Config/GRPLHCIF", timeStamp, metadata); + if (!lhcifdata) { + throw std::runtime_error("No GRPLHCIFData for run " + std::to_string(runNumber)); + } auto bfilling = lhcifdata->getBunchFilling(); std::vector bcs = bfilling.getFilledBCs(); int nbc = bcs.size(); std::cout << "Number of interacting bc:" << nbc << std::endl; // Scalers std::string srun = std::to_string(runNumber); - metadata.clear(); // can be empty + std::map metadata; metadata["runNumber"] = srun; - ccdbMgr.setURL("http://ccdb-test.cern.ch:8080"); - auto scl = ccdbMgr.getSpecific(mCCDBPathCTPScalers, timeStamp, metadata); + CTPRunScalers* scl = nullptr; + if (qc) { + ccdbMgr.setURL("http://ali-qcdb-gpn.cern.ch:8083"); + scl = ccdbMgr.getSpecific(mCCDBPathCTPScalersQC, timeStamp, metadata); + } else { + scl = ccdbMgr.getSpecific(mCCDBPathCTPScalers, timeStamp, metadata); + } if (scl == nullptr) { LOG(info) << "CTPRunScalers not in database, timestamp:" << timeStamp; return; @@ -65,6 +80,7 @@ void PlotPbLumi(int runNumber, int fillN, std::string ccdbHost = "http://ccdb-te std::vector recs = scl->getScalerRecordO2(); // // CTPConfiguration ctpcfg; + ccdbMgr.setURL("http://alice-ccdb.cern.ch"); auto ctpcfg = ccdbMgr.getSpecific(mCCDBPathCTPConfig, timeStamp, metadata); if (ctpcfg == nullptr) { LOG(info) << "CTPRunConfig not in database, timestamp:" << timeStamp; @@ -85,6 +101,7 @@ void PlotPbLumi(int runNumber, int fillN, std::string ccdbHost = "http://ccdb-te int tsc = 255; int tce = 255; int vch = 255; + int zncclsi = 255; for (auto const& cls : ctpcls) { if (cls.name.find("CMTVXTSC-B-NOPF") != std::string::npos && tsc == 255) { int itsc = cls.getIndex(); @@ -104,6 +121,12 @@ void PlotPbLumi(int runNumber, int fillN, std::string ccdbHost = "http://ccdb-te // vch = scl->getScalerIndexForClass(ivch); std::cout << cls.name << ":" << vch << ":" << ivch << std::endl; } + if (cls.name.find("C1ZNC-B-NOPF-CRU") != std::string::npos) { + int iznc = cls.getIndex(); + zncclsi = clsIndexToScaler[iznc]; + // vch = scl->getScalerIndexForClass(ivch); + std::cout << cls.name << ":" << zncclsi << ":" << iznc << std::endl; + } } if (tsc == 255 || tce == 255 || vch == 255) { std::cout << " One of dcalers not available, check config to find alternative)" << std::endl; @@ -120,11 +143,39 @@ void PlotPbLumi(int runNumber, int fillN, std::string ccdbHost = "http://ccdb-te double_t orbit0 = recs[0].intRecord.orbit; int n = recs.size() - 1; std::cout << " Run duration:" << Trun << " Scalers size:" << n + 1 << std::endl; - Double_t x[n], znc[n], zncpp[n]; - Double_t tcetsctoznc[n], tcetoznc[n], vchtoznc[n]; - for (int i = 0; i < n; i++) { - x[i] = (double_t)(recs[i + 1].intRecord.orbit + recs[i].intRecord.orbit) / 2. - orbit0; - x[i] *= 88e-6; + // + int i0 = 0; + int ilast = 0; + if (t0 != 0. || tlast != 0.) { + for (int i = 0; i < n; i++) { + double_t ttime = recs[i].epochTime - time0; + if (!i0 && t0 < ttime) { + i0 = i; + } + if (!ilast && tlast < ttime) { + ilast = i; + } + } + } else { + ilast = n; + } + n = ilast - i0; + std::cout << "i0:" << i0 << " ilast:" << ilast << std::endl; + // Double_t x[n], znc[n], zncpp[n]; + std::vector xvec(n), zncvec(n), zncppvec(n), zncclassvec(n); + Double_t* x = xvec.data(); + Double_t* znc = zncvec.data(); + Double_t* zncpp = zncppvec.data(); + Double_t* zncclass = zncclassvec.data(); + // Double_t tcetsctoznc[n], tcetoznc[n], vchtoznc[n]; + std::vector tcetsctozncvec(n), tcetozncvec(n), vchtozncvec(n); + Double_t* tcetsctoznc = tcetsctozncvec.data(); + Double_t* tcetoznc = tcetozncvec.data(); + Double_t* vchtoznc = vchtozncvec.data(); + for (int i = i0; i < ilast; i++) { + int iv = i - i0; + x[iv] = (double_t)(recs[i + 1].intRecord.orbit + recs[i].intRecord.orbit) / 2. - orbit0; + x[iv] *= 88e-6; // x[i] = (double_t)(recs[i+1].epochTime + recs[i].epochTime)/2.; double_t tt = (double_t)(recs[i + 1].intRecord.orbit - recs[i].intRecord.orbit); tt = tt * 88e-6; @@ -133,33 +184,53 @@ void PlotPbLumi(int runNumber, int fillN, std::string ccdbHost = "http://ccdb-te double_t znci = (double_t)(recs[i + 1].scalersInps[25] - recs[i].scalersInps[25]); double_t mu = -TMath::Log(1. - znci / tt / nbc / frev); double_t zncipp = mu * nbc * frev; - zncpp[i] = zncipp / 28.; - znc[i] = znci / 28. / tt; + zncpp[iv] = zncipp / 28.; + znc[iv] = znci / 28. / tt; + // znc class + znci = recs[i + 1].scalers[zncclsi].l1Before - recs[i].scalers[zncclsi].l1Before; + zncclass[iv] = znci / 28. / tt; + // std::cout << znc[i]/zncclass[i] << std::endl; // - auto had = recs[i + 1].scalers[tce].lmBefore - recs[i].scalers[tce].lmBefore; + double_t had = 0; + if (sum) { + had += recs[i + 1].scalers[tce].lmBefore - recs[i].scalers[tce].lmBefore; + } + double_t mutce = -TMath::Log(1. - had / tt / nbc / frev); // std::cout << recs[i+1].scalers[tce].lmBefore << std::endl; had += recs[i + 1].scalers[tsc].lmBefore - recs[i].scalers[tsc].lmBefore; // rat = (double_t)(had)/double_t(recs[i+1].scalersInps[25] - recs[i].scalersInps[25])*28; - tcetsctoznc[i] = (double_t)(had) / zncpp[i] / tt; + tcetsctoznc[iv] = (double_t)(had) / zncpp[iv] / tt; had = recs[i + 1].scalers[tce].lmBefore - recs[i].scalers[tce].lmBefore; // rat = (double_t)(had)/double_t(recs[i+1].scalersInps[25] - recs[i].scalersInps[25])*28; - tcetoznc[i] = (double_t)(had) / zncpp[i] / tt; + tcetoznc[iv] = (double_t)(had) / zncpp[iv] / tt; had = recs[i + 1].scalers[vch].lmBefore - recs[i].scalers[vch].lmBefore; + double_t muvch = -TMath::Log(1. - had / tt / nbc / frev); + // rat = (double_t)(had)/double_t(recs[i+1].scalersInps[25] - recs[i].scalersInps[25])*28; - vchtoznc[i] = (double_t)(had) / zncpp[i] / tt; + vchtoznc[iv] = (double_t)(had) / zncpp[iv] / tt; + // std::cout << "muzdc:" << mu << " mu tce:" << mutce << " muvch:" << muvch << std::endl; } // gStyle->SetMarkerSize(0.5); TGraph* gr1 = new TGraph(n, x, znc); + TGraph* gr11 = new TGraph(n, x, zncpp); // PileuP corrected + TGraph* gr12 = new TGraph(n, x, zncclass); // NOT PileuP corrected TGraph* gr2 = new TGraph(n, x, tcetsctoznc); TGraph* gr3 = new TGraph(n, x, tcetoznc); TGraph* gr4 = new TGraph(n, x, vchtoznc); gr1->SetMarkerStyle(20); + gr11->SetMarkerStyle(20); + gr12->SetMarkerStyle(20); + gr11->SetMarkerColor(kRed); + gr12->SetMarkerColor(kBlue); gr2->SetMarkerStyle(21); gr3->SetMarkerStyle(23); gr4->SetMarkerStyle(23); - gr1->SetTitle("R=ZNC/28 rate [Hz]; time[sec]; R"); - gr2->SetTitle("R=(TSC+TCE)*TVTX*B*28/ZNC; time[sec]; R"); + if (sum) { + gr2->SetTitle("R=(TSC+TCE)*TVTX*B*28/ZNC; time[sec]; R"); + } else { + gr2->SetTitle("R=(TSC)*TVTX*B*28/ZNC; time[sec]; R"); + } // gr2->GetHistogram()->SetMaximum(1.1); // gr2->GetHistogram()->SetMinimum(0.9); gr3->SetTitle("R=(TCE)*TVTX*B*28/ZNC; time[sec]; R"); @@ -168,10 +239,17 @@ void PlotPbLumi(int runNumber, int fillN, std::string ccdbHost = "http://ccdb-te gr4->SetTitle("R=(VCH)*TVTX*B*28/ZNC; time[sec]; R"); // gr4->GetHistogram()->SetMaximum(0.6); // gr4->GetHistogram()->SetMinimum(0.4); + TMultiGraph* mg1 = new TMultiGraph(); + mg1->SetTitle("R=ZNC/28 rate [Hz] (red=PilUp Corrected); time[sec]; R"); + mg1->Add(gr1); + mg1->Add(gr11); + mg1->Add(gr12); TCanvas* c1 = new TCanvas("c1", srun.c_str(), 200, 10, 800, 500); + std::string title = "RUN " + std::to_string(runNumber); + c1->SetTitle(title.c_str()); c1->Divide(2, 2); c1->cd(1); - gr1->Draw("AP"); + mg1->Draw("AP"); c1->cd(2); gr2->Draw("AP"); c1->cd(3); diff --git a/Detectors/CTP/macro/SaveInputsConfig.C b/Detectors/CTP/macro/SaveInputsConfig.C index 99cae77905541..459fbf4024c95 100644 --- a/Detectors/CTP/macro/SaveInputsConfig.C +++ b/Detectors/CTP/macro/SaveInputsConfig.C @@ -41,7 +41,7 @@ void SaveInputsConfig(std::string filename = "inputs.cfg", std::string ccdbHost long tmax = timeStamp + time365days; o2::ccdb::CcdbApi api; api.init(ccdbHost); // or http://localhost:8080 for a local installation - map metadata; // can be empty + std::map metadata; // can be empty // store abitrary user object in strongly typed manner api.storeAsTFileAny(&ctpcfginps, "CTP/Calib/Inputs", metadata, tmin, tmax); } diff --git a/Detectors/CTP/macro/TestFetcher.C b/Detectors/CTP/macro/TestFetcher.C index 2d73b83cd174e..b2b6912f49911 100644 --- a/Detectors/CTP/macro/TestFetcher.C +++ b/Detectors/CTP/macro/TestFetcher.C @@ -27,7 +27,7 @@ void TestFetcher(int runNumber = 557251) fetcher.setupRun(runNumber, &ccdb, ts, 0); ccdb.setURL("http://ali-qcdb-gpn.cern.ch:8083/"); std::string QCDBPathCTPScalers = "qc/CTP/Scalers"; - map metadata; // can be empty + std::map metadata; // can be empty std::string run = std::to_string(runNumber); metadata["runNumber"] = run; CTPRunScalers* ctpscalers = ccdb.getSpecific(QCDBPathCTPScalers, ts, metadata); diff --git a/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h index 9189df5d12685..8dbc5adadbfc5 100644 --- a/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h +++ b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h @@ -34,10 +34,10 @@ namespace o2 namespace ctp { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::CTP) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::CTP, 1.f, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode data to buffer with CTF diff --git a/Detectors/CTP/reconstruction/include/CTPReconstruction/RawDataDecoder.h b/Detectors/CTP/reconstruction/include/CTPReconstruction/RawDataDecoder.h index 8ebc7e0304561..53addf32c538f 100644 --- a/Detectors/CTP/reconstruction/include/CTPReconstruction/RawDataDecoder.h +++ b/Detectors/CTP/reconstruction/include/CTPReconstruction/RawDataDecoder.h @@ -60,7 +60,8 @@ class RawDataDecoder std::array getClassErrorsB() { return mClassErrorsB; } std::array getClassCountersA() { return mClassCountersA; } std::array getClassCountersB() { return mClassCountersB; } - int getLostDueToShift() { return mLostDueToShift; } + int getLostDueToShiftCls() { return mLostDueToShiftCC; } + int getLostDueToShiftInp() { return mLostDueToShiftInps; } private: static constexpr uint32_t TF_TRIGGERTYPE_MASK = 0x800; @@ -80,8 +81,8 @@ class RawDataDecoder gbtword80_t mTVXMask = 0x4; // TVX is 3rd input gbtword80_t mVBAMask = 0x20; // VBA is 6 th input bool mVerbose = false; - uint32_t mIRRejected = 0; - uint32_t mTCRRejected = 0; + int mIRRejected = 0; + int mTCRRejected = 0; bool mPadding = true; uint32_t mTFOrbit = 0; std::vector mTFOrbits; @@ -94,7 +95,8 @@ class RawDataDecoder std::array mClassErrorsB{}; // from inputs std::array mClassCountersA{}; std::array mClassCountersB{}; // from inputs - int mLostDueToShift = 0; + int mLostDueToShiftCC = 0; + int mLostDueToShiftInps = 0; CTPConfiguration mCTPConfig; }; } // namespace ctp diff --git a/Detectors/CTP/reconstruction/src/RawDataDecoder.cxx b/Detectors/CTP/reconstruction/src/RawDataDecoder.cxx index 74bd08ce943ee..a062a262acf62 100644 --- a/Detectors/CTP/reconstruction/src/RawDataDecoder.cxx +++ b/Detectors/CTP/reconstruction/src/RawDataDecoder.cxx @@ -296,12 +296,12 @@ int RawDataDecoder::decodeRaw(o2::framework::InputRecord& inputs, std::vector& digitsMap, o2::pmr::vector& digits, uint32_t TFOrbit, uint64_t trgclassmask) { // int nClasswoInp = 0; // counting classes without input which should never happen + int lost = 0; std::map digitsMapShifted; auto L0shift = o2::ctp::TriggerOffsetsParam::Instance().LM_L0; auto L1shift = L0shift + o2::ctp::TriggerOffsetsParam::Instance().L0_L1; @@ -551,7 +554,7 @@ int RawDataDecoder::shiftInputs(std::map& digit if (lut == 0 || lut == 1) { // no inps or LM digitsMapShifted[dig.first] = dig.second; } else if (lut == 2) { // L0 - shiftNew(dig.first, TFOrbit, inpmask, L0shift, 0, digitsMapShifted); + lost += shiftNew(dig.first, TFOrbit, inpmask, L0shift, 0, digitsMapShifted); if (dig.second.CTPClassMask.count()) { // LOG(error) << "Adding class mask without input ?"; // This is not needed as it can happen; Full checj done below - see next LOG(error) @@ -559,30 +562,30 @@ int RawDataDecoder::shiftInputs(std::map& digit digitsMapShifted[dig.first] = digi; } } else if (lut == 4) { // L1 - shiftNew(dig.first, TFOrbit, inpmask, L1shift, 1, digitsMapShifted); + lost += shiftNew(dig.first, TFOrbit, inpmask, L1shift, 1, digitsMapShifted); if (dig.second.CTPClassMask.count()) { CTPDigit digi = {dig.first, 0, dig.second.CTPClassMask}; digitsMapShifted[dig.first] = digi; } } else if (lut == 6) { // L0 and L1 - shiftNew(dig.first, TFOrbit, inpmask, L0shift, 0, digitsMapShifted); - shiftNew(dig.first, TFOrbit, inpmask, L1shift, 1, digitsMapShifted); + lost += shiftNew(dig.first, TFOrbit, inpmask, L0shift, 0, digitsMapShifted); + lost += shiftNew(dig.first, TFOrbit, inpmask, L1shift, 1, digitsMapShifted); if (dig.second.CTPClassMask.count()) { CTPDigit digi = {dig.first, 0, dig.second.CTPClassMask}; digitsMapShifted[dig.first] = digi; } } else if (lut == 3) { // LM and L0 - shiftNew(dig.first, TFOrbit, inpmask, L0shift, 0, digitsMapShifted); + lost += shiftNew(dig.first, TFOrbit, inpmask, L0shift, 0, digitsMapShifted); CTPDigit digi = {dig.first, inpmask & (~L0MASKInputs), dig.second.CTPClassMask}; // if LM level do not need to add class as LM is not shifted; digitsMapShifted[dig.first] = digi; } else if (lut == 5) { // LM and L1 - shiftNew(dig.first, TFOrbit, inpmask, L1shift, 1, digitsMapShifted); + lost += shiftNew(dig.first, TFOrbit, inpmask, L1shift, 1, digitsMapShifted); CTPDigit digi = {dig.first, inpmask & (~L1MASKInputs), dig.second.CTPClassMask}; digitsMapShifted[dig.first] = digi; } else if (lut == 7) { // LM and L0 and L1 - shiftNew(dig.first, TFOrbit, inpmask, L0shift, 0, digitsMapShifted); - shiftNew(dig.first, TFOrbit, inpmask, L1shift, 1, digitsMapShifted); + lost += shiftNew(dig.first, TFOrbit, inpmask, L0shift, 0, digitsMapShifted); + lost += shiftNew(dig.first, TFOrbit, inpmask, L1shift, 1, digitsMapShifted); CTPDigit digi = {dig.first, inpmaskLM, dig.second.CTPClassMask}; digitsMapShifted[dig.first] = digi; } else { @@ -592,7 +595,7 @@ int RawDataDecoder::shiftInputs(std::map& digit for (auto const& dig : digitsMapShifted) { digits.push_back(dig.second); } - return 0; + return lost; } // int RawDataDecoder::checkReadoutConsistentncy(o2::pmr::vector& digits, uint64_t trgclassmask, uint64_t trgclassmaskNoTrgDet) @@ -615,8 +618,9 @@ int RawDataDecoder::checkReadoutConsistentncy(o2::pmr::vector& digits, continue; } mClassCountersA[i]++; - if (cls->descriptor == nullptr) + if (cls->descriptor == nullptr) { continue; + } uint64_t clsinpmask = cls->descriptor->getInputsMask(); uint64_t diginpmask = digit.CTPInputMask.to_ullong(); if (!((clsinpmask & diginpmask) == clsinpmask)) { @@ -632,8 +636,9 @@ int RawDataDecoder::checkReadoutConsistentncy(o2::pmr::vector& digits, // if inps => class mask for (auto const& cls : mCTPConfig.getCTPClasses()) { // cls.printStream(std::cout); - if (cls.descriptor == nullptr) + if (cls.descriptor == nullptr) { continue; + } uint64_t clsinpmask = cls.descriptor->getInputsMask(); // class definition uint64_t diginpmask = digit.CTPInputMask.to_ullong(); uint64_t digclsmask = digit.CTPClassMask.to_ullong(); @@ -652,16 +657,13 @@ int RawDataDecoder::checkReadoutConsistentncy(o2::pmr::vector& digits, mClassErrorsB[cls.getIndex()]++; ret = 256; } else { - mLostDueToShift++; + mLostDueToShiftCC++; } } } } } } - if (mLostDueToShift) { - LOG(debug) << "LOST classes because of shift:" << mLostDueToShift; - } return ret; } // diff --git a/Detectors/CTP/simulation/src/Digitizer.cxx b/Detectors/CTP/simulation/src/Digitizer.cxx index 2f033b8a01462..b1d4ef40b7b0e 100644 --- a/Detectors/CTP/simulation/src/Digitizer.cxx +++ b/Detectors/CTP/simulation/src/Digitizer.cxx @@ -83,16 +83,16 @@ std::vector Digitizer::process(const gsl::span emcMBaccept.set(CTP_NINPUTS - 1, 1); inpmaskcoll |= emcMBaccept; } // else { // needs to be done always, remove else - for (auto const& ctpinp : det2ctpinp[o2::detectors::DetID::EMC]) { - uint64_t mask = inpmaskdebug & detInputName2Mask[ctpinp.name]; - // uint64_t mask = (inp->inputsMask).to_ullong() & detInputName2Mask[ctpinp.name]; - if (mask) { - inpmaskcoll |= std::bitset(ctpinp.inputMask); - } + for (auto const& ctpinp : det2ctpinp[o2::detectors::DetID::EMC]) { + uint64_t mask = inpmaskdebug & detInputName2Mask[ctpinp.name]; + // uint64_t mask = (inp->inputsMask).to_ullong() & detInputName2Mask[ctpinp.name]; + if (mask) { + inpmaskcoll |= std::bitset(ctpinp.inputMask); } - // } - // LOG(info) << "EMC input mask:" << inpmaskcoll << " with IR = " << currentIR.bc << ", orbit = " << currentIR.orbit; - break; + } + // } + // LOG(info) << "EMC input mask:" << inpmaskcoll << " with IR = " << currentIR.bc << ", orbit = " << currentIR.orbit; + break; } case o2::detectors::DetID::PHS: { for (auto const& ctpinp : det2ctpinp[o2::detectors::DetID::PHS]) { @@ -153,21 +153,20 @@ void Digitizer::calculateClassMask(const std::bitset ctpinpmask, st if (clustername == "emc") { tvxMBemc |= tcl.name.find("minbias_TVX_L0") != std::string::npos; // 2022 } - if (tvxMBemc || (ctpinpmask.to_ullong() & tcl.descriptor->getInputsMask()) == tcl.descriptor->getInputsMask()) { - // require real physics input in any case - if (tvxMBemc) { - // if the class is a min. bias class accept it only if the MB-accept bit is set in addition - // (fake trigger input) - if (ctpinpmask[CTP_NINPUTS - 1]) { - classmask |= tcl.classMask; - LOG(info) << "adding MBA:" << tcl.name; - } - } // else { - // EMCAL rare triggers - physical trigger input - // class identification can be handled like in the case of the other - // classes as EMCAL trigger input is required + // require real physics input in any case + if (tvxMBemc) { + // if the class is a min. bias class accept it only if the MB-accept bit is set in addition + // (fake trigger input) + if (ctpinpmask[CTP_NINPUTS - 1]) { classmask |= tcl.classMask; - // } + LOG(info) << "adding MBA:" << tcl.name; + } + } else if ((ctpinpmask.to_ullong() & tcl.descriptor->getInputsMask()) == tcl.descriptor->getInputsMask()) { + // EMCAL rare triggers - physical trigger input + // class identification can be handled like in the case of the other + // classes as EMCAL trigger input is required + LOG(info) << "adding EMCal rare trigger:" << tcl.name; + classmask |= tcl.classMask; } } else { if (tcl.descriptor && ((ctpinpmask.to_ullong() & tcl.descriptor->getInputsMask()) == tcl.descriptor->getInputsMask())) { @@ -195,7 +194,7 @@ o2::ctp::CTPConfiguration* Digitizer::getDefaultCTPConfiguration() } auto& mgr = o2::ccdb::BasicCCDBManager::instance(); mgr.setURL(mCCDBServer); - map metadata = {}; + std::map metadata = {}; long timestamp = 1546300800000; auto config = mgr.getSpecific(o2::ctp::CCDBPathCTPConfig, timestamp, metadata); diff --git a/Detectors/CTP/workflow/include/CTPWorkflow/EntropyDecoderSpec.h b/Detectors/CTP/workflow/include/CTPWorkflow/EntropyDecoderSpec.h index eee7abb08d16c..dda45c9f11a34 100644 --- a/Detectors/CTP/workflow/include/CTPWorkflow/EntropyDecoderSpec.h +++ b/Detectors/CTP/workflow/include/CTPWorkflow/EntropyDecoderSpec.h @@ -28,7 +28,7 @@ namespace ctp class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity); + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -42,7 +42,7 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt); } // namespace ctp } // namespace o2 diff --git a/Detectors/CTP/workflow/include/CTPWorkflow/EntropyEncoderSpec.h b/Detectors/CTP/workflow/include/CTPWorkflow/EntropyEncoderSpec.h index 3a023ce2022dc..a63119264e071 100644 --- a/Detectors/CTP/workflow/include/CTPWorkflow/EntropyEncoderSpec.h +++ b/Detectors/CTP/workflow/include/CTPWorkflow/EntropyEncoderSpec.h @@ -28,7 +28,7 @@ namespace ctp class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR, bool noLumi); + EntropyEncoderSpec(bool selIR, bool noLumi, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -43,7 +43,7 @@ class EntropyEncoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, bool noLumiInput = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, bool noLumiInput = false, const std::string& ctfdictOpt = "none"); } // namespace ctp } // namespace o2 diff --git a/Detectors/CTP/workflow/include/CTPWorkflow/RawDecoderSpec.h b/Detectors/CTP/workflow/include/CTPWorkflow/RawDecoderSpec.h index a5a1a75a0b594..3198e5c33e219 100644 --- a/Detectors/CTP/workflow/include/CTPWorkflow/RawDecoderSpec.h +++ b/Detectors/CTP/workflow/include/CTPWorkflow/RawDecoderSpec.h @@ -74,6 +74,17 @@ class RawDecoderSpec : public framework::Task std::deque mHistoryT; std::deque mHistoryV; RawDataDecoder mDecoder; + // Errors + int mLostDueToShiftInps = 0; + int mErrorIR = 0; + int mErrorTCR = 0; + int mIRRejected = 0; + int mTCRRejected = 0; + std::array mClsEA{}; + std::array mClsEB{}; // from inputs + std::array mClsA{}; + std::array mClsB{}; // from inputs + bool mCheckConsistency = false; }; /// \brief Creating DataProcessorSpec for the CTP diff --git a/Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx b/Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx index 8c2f5d05aa031..0fa8fb0004e4c 100644 --- a/Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx @@ -24,8 +24,7 @@ namespace o2 { namespace ctp { - -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); @@ -90,7 +89,7 @@ void EntropyDecoderSpec::updateTimeDependentParams(framework::ProcessingContext& } } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"digits"}, "CTP", "DIGITS", 0, Lifetime::Timeframe}, @@ -99,18 +98,19 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) std::vector inputs; inputs.emplace_back("ctf_CTP", "CTP", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_CTP", "CTP", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("CTP/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_CTP", "CTP", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("CTP/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); inputs.emplace_back("ctpconfig", "CTP", "CTPCONFIG", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/Config", 1)); return DataProcessorSpec{ "ctp-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ignore-ctpinputs-decoding-ctf", VariantType::Bool, false, {"Inputs alignment: false - CTF decoder - has to be compatible with reco: allowed options: 10,01,00"}}, + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"ignore-ctpinputs-decoding-ctf", VariantType::Bool, false, {"Inputs alignment: false - CTF decoder - has to be compatible with reco: allowed options: 10,01,00"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace ctp } // namespace o2 diff --git a/Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx b/Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx index 44e64d7505977..902fe22dadcc9 100644 --- a/Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx @@ -25,8 +25,7 @@ namespace o2 { namespace ctp { - -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, bool nolumi) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR), mNoLumi(nolumi) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, bool nolumi, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR), mNoLumi(nolumi) { mTimer.Stop(); mTimer.Reset(); @@ -77,14 +76,17 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR, bool nolumi) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, bool nolumi, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("digits", "CTP", "DIGITS", 0, Lifetime::Timeframe); if (!nolumi) { inputs.emplace_back("CTPLumi", "CTP", "LUMI", 0, Lifetime::Timeframe); } - inputs.emplace_back("ctfdict", "CTP", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("CTP/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "CTP", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("CTP/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -92,13 +94,11 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR, bool nolumi) "ctp-entropy-encoder", inputs, Outputs{{"CTP", "CTFDATA", 0, Lifetime::Timeframe}, {{"ctfrep"}, "CTP", "CTFENCREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR, nolumi)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(selIR, nolumi, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace ctp } // namespace o2 diff --git a/Detectors/CTP/workflow/src/RawDecoderSpec.cxx b/Detectors/CTP/workflow/src/RawDecoderSpec.cxx index 3f7c729b351a3..041e6cb472ebb 100644 --- a/Detectors/CTP/workflow/src/RawDecoderSpec.cxx +++ b/Detectors/CTP/workflow/src/RawDecoderSpec.cxx @@ -26,6 +26,8 @@ using namespace o2::ctp::reco_workflow; void RawDecoderSpec::init(framework::InitContext& ctx) { + mCheckConsistency = ctx.options().get("check-consistency"); + mDecoder.setCheckConsistency(mCheckConsistency); mDecodeinputs = ctx.options().get("ctpinputs-decoding"); mDecoder.setDecodeInps(mDecodeinputs); mNTFToIntegrate = ctx.options().get("ntf-to-average"); @@ -43,7 +45,7 @@ void RawDecoderSpec::init(framework::InitContext& ctx) mOutputLumiInfo.inp2 = inp2; mMaxInputSize = ctx.options().get("max-input-size"); mMaxInputSizeFatal = ctx.options().get("max-input-size-fatal"); - LOG(info) << "CTP reco init done. Inputs decoding here:" << mDecodeinputs << " DoLumi:" << mDoLumi << " DoDigits:" << mDoDigits << " NTF:" << mNTFToIntegrate << " Lumi inputs:" << lumiinp1 << ":" << inp1 << " " << lumiinp2 << ":" << inp2 << " Max errors:" << maxerrors << " Max input size:" << mMaxInputSize << " MaxInputSizeFatal:" << mMaxInputSizeFatal; + LOG(info) << "CTP reco init done. Inputs decoding here:" << mDecodeinputs << " DoLumi:" << mDoLumi << " DoDigits:" << mDoDigits << " NTF:" << mNTFToIntegrate << " Lumi inputs:" << lumiinp1 << ":" << inp1 << " " << lumiinp2 << ":" << inp2 << " Max errors:" << maxerrors << " Max input size:" << mMaxInputSize << " MaxInputSizeFatal:" << mMaxInputSizeFatal << " CheckConsistency:" << mCheckConsistency; // mOutputLumiInfo.printInputs(); } void RawDecoderSpec::endOfStream(framework::EndOfStreamContext& ec) @@ -69,20 +71,22 @@ void RawDecoderSpec::endOfStream(framework::EndOfStreamContext& ec) o0 = TFOrbits[i]; } std::cout << std::endl; - LOG(info) << " Lost due to the shift:" << mDecoder.getLostDueToShift(); - LOG(info) << "Number of missing TF:" << nmiss << std::endl; - if (mDecoder.getErrorIR() || mDecoder.getErrorTCR()) - LOG(error) << "# of IR errors:" << mDecoder.getErrorIR() << " TCR errors:" << mDecoder.getErrorTCR() << std::endl; - std::array clsA = mDecoder.getClassCountersA(); - std::array clsB = mDecoder.getClassCountersB(); - std::array clsEA = mDecoder.getClassErrorsA(); - std::array clsEB = mDecoder.getClassErrorsB(); - - for (int i = 0; i < o2::ctp::CTP_NCLASSES; i++) { - bool print = clsA[i] > 0 || clsB[i] > 0 || clsEA[i] > 0 || clsEB[i] > 0; - if (clsEA[i]) - LOG(error) << " Class without inputs:"; - LOG(important) << "CLASS:" << i << " Cls=>Inp:" << clsA[i] << " Inp=>Cls:" << clsB[i] << " ErrorsCls=>Inps:" << clsEA[i] << " MissingInps=>Cls:" << clsEB[i]; + LOG(info) << "Number of non continous TF:" << nmiss << std::endl; + LOG(info) << "Lost in shiftInputs:" << mLostDueToShiftInps; + LOG(info) << "Lost in addDigit Inputs:" << mIRRejected << " Classes:" << mTCRRejected; + if (mErrorIR || mErrorTCR) { + LOG(error) << "# of IR errors:" << mErrorIR << " TCR errors:" << mErrorTCR << std::endl; + } + if (mCheckConsistency) { + LOG(info) << "Lost due to the shift Consistency Checker:" << mDecoder.getLostDueToShiftCls(); + auto ctpcfg = mDecoder.getCTPConfig(); + for (int i = 0; i < o2::ctp::CTP_NCLASSES; i++) { + std::string name = ctpcfg.getClassNameFromIndex(i); + if (mClsEA[i]) { + LOG(error) << " Class without inputs:"; + } + LOG(important) << "CLASS:" << name << ":" << i << " Cls=>Inp:" << mClsA[i] << " Inp=>Cls:" << mClsB[i] << " ErrorsCls=>Inps:" << mClsEA[i] << " MissingInps=>Cls:" << mClsEB[i]; + } } } void RawDecoderSpec::run(framework::ProcessingContext& ctx) @@ -159,6 +163,21 @@ void RawDecoderSpec::run(framework::ProcessingContext& ctx) if (mDoDigits) { LOG(info) << "[CTPRawToDigitConverter - run] Writing " << mOutputDigits.size() << " digits. IR rejected:" << mDecoder.getIRRejected() << " TCR rejected:" << mDecoder.getTCRRejected(); ctx.outputs().snapshot(o2::framework::Output{"CTP", "DIGITS", 0}, mOutputDigits); + mLostDueToShiftInps += mDecoder.getLostDueToShiftInp(); + mErrorIR += mDecoder.getErrorIR(); + mErrorTCR += mDecoder.getErrorTCR(); + mIRRejected += mDecoder.getIRRejected(); + mTCRRejected += mDecoder.getTCRRejected(); + auto clsEA = mDecoder.getClassErrorsA(); + auto clsEB = mDecoder.getClassErrorsB(); + auto cntCA = mDecoder.getClassCountersA(); + auto cntCB = mDecoder.getClassCountersB(); + for (int i = 0; i < o2::ctp::CTP_NCLASSES; i++) { + mClsEA[i] += clsEA[i]; + mClsEB[i] += clsEB[i]; + mClsA[i] += cntCA[i]; + mClsB[i] += cntCB[i]; + } } if (mDoLumi) { uint32_t tfCountsT = 0; @@ -234,7 +253,8 @@ o2::framework::DataProcessorSpec o2::ctp::reco_workflow::getRawDecoderSpec(bool {"lumi-inp2", o2::framework::VariantType::String, "VBA", {"The second input used for online lumi. Name in capital."}}, {"use-verbose-mode", o2::framework::VariantType::Bool, false, {"Verbose logging"}}, {"max-input-size", o2::framework::VariantType::Int, 0, {"Do not process input if bigger than max size, 0 - do not check"}}, - {"max-input-size-fatal", o2::framework::VariantType::Bool, false, {"If true issue fatal error otherwise error on;y"}}, + {"max-input-size-fatal", o2::framework::VariantType::Bool, false, {"If true issue fatal error otherwise error only"}}, + {"check-consistency", o2::framework::VariantType::Bool, false, {"If true checks digits consistency using ctp config"}}, {"ctpinputs-decoding", o2::framework::VariantType::Bool, false, {"Inputs alignment: true - raw decoder - has to be compatible with CTF decoder: allowed options: 10,01,00"}}}}; } void RawDecoderSpec::updateTimeDependentParams(framework::ProcessingContext& pc) diff --git a/Detectors/CTP/workflow/src/entropy-encoder-workflow.cxx b/Detectors/CTP/workflow/src/entropy-encoder-workflow.cxx index 1fcaa89be9888..c2b324a4b3bfa 100644 --- a/Detectors/CTP/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/CTP/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "none", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"no-lumi-input", VariantType::Bool, false, {"Lumi info not available"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; @@ -38,6 +39,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::ctp::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("no-lumi-input"))); + wf.emplace_back(o2::ctp::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("no-lumi-input"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/CTP/workflowScalers/CMakeLists.txt b/Detectors/CTP/workflowScalers/CMakeLists.txt index a31774ac66d69..f02a7f33e2abd 100644 --- a/Detectors/CTP/workflowScalers/CMakeLists.txt +++ b/Detectors/CTP/workflowScalers/CMakeLists.txt @@ -34,3 +34,11 @@ o2_add_executable( SOURCES src/ctp-ccdb-orbit.cxx PUBLIC_LINK_LIBRARIES O2::DataFormatsCTP Boost::program_options) +o2_add_executable( + bk-write + COMPONENT_NAME ctp + SOURCES src/ctp-bk-write.cxx + PUBLIC_LINK_LIBRARIES O2::DataFormatsCTP + O2::CTPWorkflowScalers + AliceO2::BookkeepingApi + Boost::program_options) diff --git a/Detectors/CTP/workflowScalers/include/CTPWorkflowScalers/ctpCCDBManager.h b/Detectors/CTP/workflowScalers/include/CTPWorkflowScalers/ctpCCDBManager.h index 4237ad4501fcc..df2aa79d18697 100644 --- a/Detectors/CTP/workflowScalers/include/CTPWorkflowScalers/ctpCCDBManager.h +++ b/Detectors/CTP/workflowScalers/include/CTPWorkflowScalers/ctpCCDBManager.h @@ -31,8 +31,9 @@ class ctpCCDBManager int saveOrbitReset(long timeStamp); int saveCtpCfg(uint32_t runNumber, long timeStamp); static CTPConfiguration getConfigFromCCDB(long timestamp, std::string run, bool& ok); - static CTPConfiguration getConfigFromCCDB(long timestamp, std::string run); - CTPRunScalers getScalersFromCCDB(long timestamp, std::string, bool& ok); + CTPConfiguration getConfigFromCCDB(long timestamp, std::string run); + CTPRunScalers getScalersFromCCDB(long timestamp, std::string run, bool& ok); + static CTPRunScalers getScalersFromCCDB(long timestamp, std::string, std::string path, bool& ok); static void setCCDBHost(std::string host) { mCCDBHost = host; }; static void setQCDBHost(std::string host) { mQCDBHost = host; }; void setCtpCfgDir(std::string& ctpcfgdir) { mCtpCfgDir = ctpcfgdir; }; diff --git a/Detectors/CTP/workflowScalers/src/RunManager.cxx b/Detectors/CTP/workflowScalers/src/RunManager.cxx index 054505aea7ba6..778677bec2ec9 100644 --- a/Detectors/CTP/workflowScalers/src/RunManager.cxx +++ b/Detectors/CTP/workflowScalers/src/RunManager.cxx @@ -216,14 +216,14 @@ int CTPRunManager::addScalers(uint32_t irun, std::time_t time, bool start) } scalrec.intRecord.bc = 0; mActiveRuns[irun]->scalers.addScalerRacordRaw(scalrec); - LOG(info) << "Adding scalers for orbit:" << scalrec.intRecord.orbit; + LOG(debug) << "Adding scalers for orbit:" << scalrec.intRecord.orbit; // scalrec.printStream(std::cout); // printCounters(); return 0; } int CTPRunManager::processMessage(std::string& topic, const std::string& message) { - LOG(info) << "Processing message with topic:" << topic; + LOG(debug) << "Processing message with topic:" << topic; std::string firstcounters; if (topic.find("clear") != std::string::npos) { mRunsLoaded.clear(); @@ -283,7 +283,7 @@ int CTPRunManager::processMessage(std::string& topic, const std::string& message // get config size_t irun = message.find("run"); if (irun == std::string::npos) { - LOG(warning) << "run keyword not found in SOX"; + LOG(debug) << "run keyword not found in SOX"; irun = message.size(); } LOG(info) << "SOX received, Run keyword position:" << irun; @@ -319,22 +319,22 @@ int CTPRunManager::processMessage(std::string& topic, const std::string& message } double timeStamp = std::stold(tokens.at(0)); std::time_t tt = timeStamp; - LOG(info) << "Processing scalers, all good, time:" << tokens.at(0) << " " << std::asctime(std::localtime(&tt)); + LOG(debug) << "Processing scalers, all good, time:" << tokens.at(0) << " " << std::asctime(std::localtime(&tt)); for (uint32_t i = 1; i < tokens.size(); i++) { mCounters[i - 1] = std::stoull(tokens.at(i)); if (i < (NRUNS + 1)) { - std::cout << mCounters[i - 1] << " "; + // std::cout << mCounters[i - 1] << " "; } } - std::cout << std::endl; - LOG(info) << "Counter size:" << tokens.size(); + // std::cout << std::endl; + LOG(debug) << "Counter size:" << tokens.size(); // for (uint32_t i = 0; i < NRUNS; i++) { if ((mCounters[i] == 0) && (mActiveRunNumbers[i] == 0)) { // not active } else if ((mCounters[i] != 0) && (mActiveRunNumbers[i] == mCounters[i])) { // active , do scalers - LOG(info) << "Run continue:" << mCounters[i]; + LOG(debug) << "Run continue:" << mCounters[i]; addScalers(i, tt); // LOG(info) << " QC period:" << mActiveRunNumbers[i] << " " << mActiveRuns[i]->qcwpcount << " " << mQCWritePeriod; if (mActiveRuns[i]->qcwpcount > mQCWritePeriod) { @@ -367,7 +367,7 @@ int CTPRunManager::processMessage(std::string& topic, const std::string& message } } mEOX = 0; - printActiveRuns(); + // printActiveRuns(); return 0; } void CTPRunManager::printActiveRuns() const diff --git a/Detectors/CTP/workflowScalers/src/ctp-bk-write.cxx b/Detectors/CTP/workflowScalers/src/ctp-bk-write.cxx new file mode 100644 index 0000000000000..8460c07dcc896 --- /dev/null +++ b/Detectors/CTP/workflowScalers/src/ctp-bk-write.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. + +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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: +// +#include +#include +#include +#include +#include "CommonUtils/StringUtils.h" +#include +#include "CTPWorkflowScalers/ctpCCDBManager.h" +#include "BookkeepingApi/BkpClientFactory.h" +#include "BookkeepingApi/BkpClient.h" +#include +#include +#include +#include +namespace bpo = boost::program_options; +// +// Test in the lab +// o2-ctp-bk-write -r 37 -s 1 -c 1 --ccdb='http://acsl-ccdb.cern.ch:8083' -b 'acsl-aliecs.cern.ch:4001' -t 1753185071753 +// +int main(int argc, char** argv) +{ + const std::string testCCDB = "http://ccdb-test.cern.ch:8080"; + // std::string prodCCDB = "http://o2-ccdb.internal"; + const std::string aliceCCDB = "http://alice-ccdb.cern.ch"; + bpo::variables_map vm; + bpo::options_description opt_general("Usage:\n " + std::string(argv[0]) + + " Write ctp config or scalers to BK\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,f", bpo::value()->default_value("none"), "input file name, none - do not read file"); + add_option("bkhost,b", bpo::value()->default_value("none"), "bk web address"); + add_option("ccdb", bpo::value()->default_value("alice"), "choose databse: test- test ccdb; prod - production ccdb; alice - alice ccdb; else ccdb parameter"); + add_option("run-number,r", bpo::value()->default_value(0), "run number"); + add_option("timestamp,t", bpo::value()->default_value(0), "timestamp; if 0 timestamp is calulated inside this code"); + add_option("cfg,c", bpo::value()->default_value(0), "Do cfg"); + add_option("scalers,s", bpo::value()->default_value(0), "Do scalers"); + // + 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); + } + uint64_t timestamp = vm["timestamp"].as(); + // + int ret = 0; + std::vector runs; + int32_t run = vm["run-number"].as(); + std::cout << "run:" << run << std::endl; + if (run) { + std::cout << "pushing" << std::endl; + runs.push_back(std::to_string(run)); + } + // read input file + std::string filename = vm["input-file"].as(); + if (filename != "none") { + std::ifstream file(filename); + if (!file.is_open()) { + LOG(fatal) << "Cannot open file:" << filename << std::endl; + } else { + std::string line; + while (std::getline(file, line)) { + std::cout << line << "\n"; + std::vector tokens = o2::utils::Str::tokenize(line, ' '); + // int run = std::stoi(tokens[0]); + runs.push_back(tokens[0]); + } + } + } + bool cfg = vm["cfg"].as(); + bool scalers = vm["scalers"].as(); + std::cout << "Doing: cfg:" << cfg << " scal:" << scalers << std::endl; + if (cfg || scalers) { + std::string bkhost = vm["bkhost"].as(); + std::unique_ptr mBKClient = o2::bkp::api::BkpClientFactory::create(bkhost); + // get from ccdb + std::string ccdbAddress; + if (vm["ccdb"].as() == "prod") { + // ccdbAddress = prodCCDB; + } else if (vm["ccdb"].as() == "test") { + ccdbAddress = testCCDB; + } else if (vm["ccdb"].as() == "alice") { + ccdbAddress = aliceCCDB; + } else { + ccdbAddress = vm["ccdb"].as(); + } + o2::ctp::ctpCCDBManager::setCCDBHost(ccdbAddress); + std::cout << "CCDB: " << vm["ccdb"].as() << " " << ccdbAddress << std::endl; + std::map metadata; + for (auto const& run : runs) { + metadata["runNumber"] = run; + bool ok; + int runNumber = std::stoi(run); + auto ctpcfg = o2::ctp::ctpCCDBManager::getConfigFromCCDB(timestamp, run, ok); + + if (cfg) { + std::string ctpcfgstr = ctpcfg.getConfigString(); + try { + mBKClient->run()->setRawCtpTriggerConfiguration(runNumber, ctpcfgstr); + } catch (std::runtime_error& error) { + std::cerr << "An error occurred: " << error.what() << std::endl; + // return 1; + } + LOG(info) << "Run BK:" << run << " CFG:" << cfg; + } + if (scalers) { + auto ctpcnts = o2::ctp::ctpCCDBManager::getScalersFromCCDB(timestamp, run, "CTP/Calib/Scalers", ok); + ctpcnts.convertRawToO2(); + std::vector clsinds = ctpcnts.getClassIndexes(); + long ts = ctpcnts.getTimeLimit().second; + int i = 0; + for (auto const& ind : clsinds) { + std::array cntsbk = ctpcnts.getIntegralForClass(i); + std::string clsname = ctpcfg.getClassNameFromHWIndex(cntsbk[0]); + try { + mBKClient->ctpTriggerCounters()->createOrUpdateForRun(runNumber, clsname, ts, cntsbk[1], cntsbk[2], cntsbk[3], cntsbk[4], cntsbk[5], cntsbk[6]); + std::cout << runNumber << " clsname: " << cntsbk[0] << " " << clsname << " t:" << ts << " cnts:" << cntsbk[1] << " " << cntsbk[2] << " " << cntsbk[3] << " " << cntsbk[4] << " " << cntsbk[5] << " " << cntsbk[6] << std::endl; + ; + + } catch (std::runtime_error& error) { + std::cerr << "An error occurred: " << error.what() << std::endl; + // return 1; + } + LOG(debug) << "Run BK scalers ok"; + i++; + } + } + } + // add to bk + } + std::cout << "o2-ctp-bk-write done" << std::endl; + return ret; +} diff --git a/Detectors/CTP/workflowScalers/src/ctp-ccdb-orbit.cxx b/Detectors/CTP/workflowScalers/src/ctp-ccdb-orbit.cxx index 7dedcacbf6047..aa953e89264ef 100644 --- a/Detectors/CTP/workflowScalers/src/ctp-ccdb-orbit.cxx +++ b/Detectors/CTP/workflowScalers/src/ctp-ccdb-orbit.cxx @@ -124,7 +124,12 @@ int main(int argc, char** argv) ret = api.storeAsTFileAny(&(vect), ccdbPath, metadata, tmin, tmax); } else { std::cout << "Storing:" << ccdbPath << " tmin:" << tmin << " tmax:" << tmax << " ts:" << tt << std::endl; + std::string filename = "orbitReset.root"; + auto classname = "std::vector"; + metadata["adjustableEOV"] = "true"; ret = api.storeAsTFileAny(&(vect), ccdbPath, metadata, tmin, tmax); + o2::ccdb::CcdbObjectInfo oi(ccdbPath, classname, filename, metadata, tmin, tmax); + adjustOverriddenEOV(api, oi); } } // diff --git a/Detectors/CTP/workflowScalers/src/ctp-proxy.cxx b/Detectors/CTP/workflowScalers/src/ctp-proxy.cxx index f8f8ad3c95fbb..391d1b5ccf58b 100644 --- a/Detectors/CTP/workflowScalers/src/ctp-proxy.cxx +++ b/Detectors/CTP/workflowScalers/src/ctp-proxy.cxx @@ -56,6 +56,7 @@ InjectorFunction dcs2dpl(std::string& ccdbhost, std::string& bkhost, std::string runMgr->setCtpCfgDir(ctpcfgdir); runMgr->init(); // runMgr->setClient(client); + static int nprint = 0; return [runMgr](TimingInfo&, ServiceRegistryRef const& services, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) -> bool { // FIXME: Why isn't this function using the timeslice index? // make sure just 2 messages received @@ -66,7 +67,15 @@ InjectorFunction dcs2dpl(std::string& ccdbhost, std::string& bkhost, std::string std::string messageHeader{static_cast(parts.At(0)->GetData()), parts.At(0)->GetSize()}; size_t dataSize = parts.At(1)->GetSize(); std::string messageData{static_cast(parts.At(1)->GetData()), parts.At(1)->GetSize()}; - LOG(info) << "received message " << messageHeader << " of size " << dataSize << " # parts:" << parts.Size(); // << " Payload:" << messageData; + nprint++; + int nlimit = 60; + int nrange = 8; + if (nprint > nlimit && nprint < (nlimit + nrange + 1)) { + LOG(info) << "received message " << messageHeader << " of size " << dataSize << " # parts:" << parts.Size(); // << " Payload:" << messageData; + if (nprint == (nlimit + nrange)) { + nprint = 0; + } + } runMgr->processMessage(messageHeader, messageData); return true; }; diff --git a/Detectors/CTP/workflowScalers/src/ctpCCDBManager.cxx b/Detectors/CTP/workflowScalers/src/ctpCCDBManager.cxx index 58850d88eb2c6..74d4a905c93e2 100644 --- a/Detectors/CTP/workflowScalers/src/ctpCCDBManager.cxx +++ b/Detectors/CTP/workflowScalers/src/ctpCCDBManager.cxx @@ -28,7 +28,7 @@ int ctpCCDBManager::saveRunScalersToCCDB(CTPRunScalers& scalers, long timeStart, { // data base if (mCCDBHost == "none") { - LOG(info) << "Scalers not written to CCDB none"; + LOG(debug) << "Scalers not written to CCDB none"; return 0; } // CTPActiveRun* run = mActiveRuns[i]; @@ -40,7 +40,7 @@ int ctpCCDBManager::saveRunScalersToCCDB(CTPRunScalers& scalers, long timeStart, long tmin = timeStart - time10min; long tmax = timeStop + time3days; o2::ccdb::CcdbApi api; - map metadata; // can be empty + std::map metadata; // can be empty metadata["runNumber"] = std::to_string(scalers.getRunNumber()); api.init(mCCDBHost.c_str()); // or http://localhost:8080 for a local installation // store abitrary user object in strongly typed manner @@ -56,7 +56,7 @@ int ctpCCDBManager::saveRunScalersToQCDB(CTPRunScalers& scalers, long timeStart, { // data base if (mQCDBHost == "none") { - LOG(info) << "Scalers not written to QCDB none"; + LOG(debug) << "Scalers not written to QCDB none"; return 0; } // CTPActiveRun* run = mActiveRuns[i];q @@ -68,7 +68,7 @@ int ctpCCDBManager::saveRunScalersToQCDB(CTPRunScalers& scalers, long timeStart, long tmin = timeStart - time10min; long tmax = timeStop + time3days; o2::ccdb::CcdbApi api; - map metadata; // can be empty + std::map metadata; // can be empty metadata["runNumber"] = std::to_string(scalers.getRunNumber()); api.init(mQCDBHost.c_str()); // or http://localhost:8080 for a local installation // store abitrary user object in strongly typed manner @@ -95,7 +95,7 @@ int ctpCCDBManager::saveRunConfigToCCDB(CTPConfiguration* cfg, long timeStart) long tmin = timeStart - time10min; long tmax = timeStart + time3days; o2::ccdb::CcdbApi api; - map metadata; // can be empty + std::map metadata; // can be empty metadata["runNumber"] = std::to_string(cfg->getRunNumber()); api.init(mCCDBHost.c_str()); // or http://localhost:8080 for a local installation // store abitrary user object in strongly typed manner @@ -125,7 +125,7 @@ int ctpCCDBManager::saveSoxOrbit(uint32_t runNumber, uint32_t soxOrbit, long tim long tmin = timestamp / 1000; long tmax = tmin + 381928219; o2::ccdb::CcdbApi api; - map metadata; // can be empty + std::map metadata; // can be empty metadata["runNumber"] = std::to_string(runNumber); api.init(mCCDBHost.c_str()); // or http://localhost:8080 for a local installation @@ -155,11 +155,16 @@ int ctpCCDBManager::saveOrbitReset(long timeStamp) long tmin = timeStamp / 1000; long tmax = tmin + 381928219; o2::ccdb::CcdbApi api; - map metadata; // can be empty + std::map metadata; // can be empty api.init(mCCDBHost.c_str()); // or http://localhost:8080 for a local installation - - // store abitrary user object in strongly typed manner - int ret = api.storeAsTFileAny(&vect, mCCDBPathOrbitReset, metadata, tmin, tmax); + // int ret = api.storeAsTFileAny(&vect, mCCDBPathOrbitReset, metadata, tmin, tmax); + std::cout << "Storing:" << mCCDBPathOrbitReset << " tmin:" << tmin << " tmax:" << tmax << " ts:" << timeStamp << std::endl; + std::string filename = "orbitReset.root"; + auto classname = "std::vector"; + metadata["adjustableEOV"] = "true"; + int ret = api.storeAsTFileAny(&(vect), mCCDBPathOrbitReset, metadata, tmin, tmax); + o2::ccdb::CcdbObjectInfo oi(mCCDBPathOrbitReset, classname, filename, metadata, tmin, tmax); + adjustOverriddenEOV(api, oi); if (ret == 0) { LOG(info) << "Orbit reset saved in ccdb:" << mCCDBHost << " tmin:" << tmin << " tmax:" << tmax; } else { @@ -184,7 +189,7 @@ int ctpCCDBManager::saveCtpCfg(uint32_t runNumber, long timeStart) long tmin = timeStart - time10min; long tmax = timeStart + time3days; o2::ccdb::CcdbApi api; - map metadata; // can be empty + std::map metadata; // can be empty metadata["runNumber"] = std::to_string(runNumber); api.init(mCCDBHost.c_str()); // or http://localhost:8080 for a local installation // store abitrary user object in strongly typed manner @@ -199,10 +204,16 @@ int ctpCCDBManager::saveCtpCfg(uint32_t runNumber, long timeStart) } CTPConfiguration ctpCCDBManager::getConfigFromCCDB(long timestamp, std::string run, bool& ok) { + auto& mgr = o2::ccdb::BasicCCDBManager::instance(); mgr.setURL(mCCDBHost); - map metadata; // can be empty + std::map metadata; // can be empty metadata["runNumber"] = run; + if (timestamp == 0) { + // Timestamp + auto soreor = mgr.getRunDuration(std::stoi(run)); + timestamp = (soreor.second - soreor.first) / 2 + soreor.first; + } auto ctpconfigdb = mgr.getSpecific(CCDBPathCTPConfig, timestamp, metadata); if (ctpconfigdb == nullptr) { LOG(info) << "CTP config not in database, timestamp:" << timestamp; @@ -228,7 +239,7 @@ CTPRunScalers ctpCCDBManager::getScalersFromCCDB(long timestamp, std::string run { auto& mgr = o2::ccdb::BasicCCDBManager::instance(); mgr.setURL(mCCDBHost); - map metadata; // can be empty + std::map metadata; // can be empty metadata["runNumber"] = run; auto ctpscalers = mgr.getSpecific(mCCDBPathCTPScalers, timestamp, metadata); if (ctpscalers == nullptr) { @@ -240,3 +251,24 @@ CTPRunScalers ctpCCDBManager::getScalersFromCCDB(long timestamp, std::string run } return *ctpscalers; } +CTPRunScalers ctpCCDBManager::getScalersFromCCDB(long timestamp, std::string run, std::string path, bool& ok) +{ + auto& mgr = o2::ccdb::BasicCCDBManager::instance(); + mgr.setURL(mCCDBHost); + std::map metadata; // can be empty + metadata["runNumber"] = run; + if (timestamp == 0) { + // Timestamp + auto soreor = mgr.getRunDuration(std::stoi(run)); + timestamp = (soreor.second - soreor.first) / 2 + soreor.first; + } + auto ctpscalers = mgr.getSpecific(path, timestamp, metadata); + if (ctpscalers == nullptr) { + LOG(info) << "CTPRunScalers not in database, timestamp:" << timestamp; + ok = 0; + } else { + // ctpscalers->printStream(std::cout); + ok = 1; + } + return *ctpscalers; +} \ No newline at end of file diff --git a/Detectors/Calibration/include/DetectorsCalibration/IntegratedClusterCalibrator.h b/Detectors/Calibration/include/DetectorsCalibration/IntegratedClusterCalibrator.h index 8a6996c35f2b3..9720142d391b1 100644 --- a/Detectors/Calibration/include/DetectorsCalibration/IntegratedClusterCalibrator.h +++ b/Detectors/Calibration/include/DetectorsCalibration/IntegratedClusterCalibrator.h @@ -331,6 +331,9 @@ struct TimeSeriesdEdx { }; struct TimeSeriesITSTPC { + float mVDrift = 0; ///< drift velocity in cm/us + float mPressure = 0; ///< pressure + float mTemperature = 0; ///< temperature TimeSeries mTSTPC; ///< TPC standalone DCAs TimeSeries mTSITSTPC; ///< ITS-TPC standalone DCAs ITSTPC_Matching mITSTPCAll; ///< ITS-TPC matching efficiency for ITS standalone + afterburner @@ -499,7 +502,7 @@ struct TimeSeriesITSTPC { nVertexContributors_Quantiles.resize(nTotalQ); } - ClassDefNV(TimeSeriesITSTPC, 5); + ClassDefNV(TimeSeriesITSTPC, 6); }; } // end namespace tpc diff --git a/Detectors/Calibration/include/DetectorsCalibration/TimeSlotCalibration.h b/Detectors/Calibration/include/DetectorsCalibration/TimeSlotCalibration.h index 87562afddf2ca..a8be3644619a4 100644 --- a/Detectors/Calibration/include/DetectorsCalibration/TimeSlotCalibration.h +++ b/Detectors/Calibration/include/DetectorsCalibration/TimeSlotCalibration.h @@ -281,6 +281,15 @@ template template bool TimeSlotCalibration::process(const DATA&... data) { + if (mCurrentTFInfo.discard) { + LOGP(warn, "Ignoring TF with discard flag on: Orbit {}, TFcounter {}, Run:{}, StartTime:{} CreationTime {}, ", + mCurrentTFInfo.firstTForbit, + mCurrentTFInfo.tfCounter, + mCurrentTFInfo.runNumber, + mCurrentTFInfo.startTime, + mCurrentTFInfo.creation); + return false; // ignore bad TF + } static bool firstCall = true; if (firstCall) { firstCall = false; diff --git a/Detectors/Calibration/testMacros/getRunParameters.cxx b/Detectors/Calibration/testMacros/getRunParameters.cxx index c06926511c95d..d3f9b0a2ece69 100644 --- a/Detectors/Calibration/testMacros/getRunParameters.cxx +++ b/Detectors/Calibration/testMacros/getRunParameters.cxx @@ -53,6 +53,18 @@ void writeDurationToFile(long duration) fclose(fptr); } +void writeSORToFile(long sor) +{ + + FILE* fptr = fopen("SOR.txt", "w"); + if (fptr == nullptr) { + LOGP(fatal, "ERROR: Could not open file to write SOR!"); + return; + } + fprintf(fptr, "%ld", sor); + fclose(fptr); +} + void writeBFieldToFile(float b) { @@ -165,6 +177,7 @@ int main(int argc, char* argv[]) ir = -1.f; writeIRtoFile(ir); writeDurationToFile(run_O2duration); + writeSORToFile(tsSOR); return 0; } } @@ -204,6 +217,7 @@ int main(int argc, char* argv[]) } writeIRtoFile(ir); writeDurationToFile(duration); + writeSORToFile(tsSOR); return 0; } diff --git a/Detectors/DCS/include/DetectorsDCS/DataPointCompositeObject.h b/Detectors/DCS/include/DetectorsDCS/DataPointCompositeObject.h index 9aaf6e517336d..84e15e4656cd2 100644 --- a/Detectors/DCS/include/DetectorsDCS/DataPointCompositeObject.h +++ b/Detectors/DCS/include/DetectorsDCS/DataPointCompositeObject.h @@ -28,9 +28,7 @@ #include "DetectorsDCS/DataPointValue.h" #include "DetectorsDCS/DeliveryType.h" -namespace o2 -{ -namespace dcs +namespace o2::dcs { /** * DataPointCompositeObject is a composition of a DataPointIdentifier and a @@ -47,7 +45,7 @@ struct DataPointCompositeObject final { * * @see ADAPRO::ADAPOS::DataPointIdentifier */ - const DataPointIdentifier id; + DataPointIdentifier id; /** * The DataPointValue object, which occupies the last 64 bytes of the @@ -83,15 +81,9 @@ struct DataPointCompositeObject final { /** * Copy constructor */ - DataPointCompositeObject(const DataPointCompositeObject& src) noexcept : DataPointCompositeObject(src.id, src.data) {} + DataPointCompositeObject(const DataPointCompositeObject& src) noexcept = default; - DataPointCompositeObject& operator=(const DataPointCompositeObject& src) noexcept - { - if (&src != this) { - memcpy(this, &src, sizeof(DataPointCompositeObject)); - } - return *this; - } + DataPointCompositeObject& operator=(const DataPointCompositeObject& src) noexcept = default; /** * Bit-by bit equality comparison of DataPointCompositeObjects. @@ -297,26 +289,6 @@ struct DataPointCompositeObject final { template T getValue(const DataPointCompositeObject& dpcom); -} // namespace dcs - -/// Defining DataPointCompositeObject explicitly as messageable -namespace framework -{ -template -struct is_messageable; -template <> -struct is_messageable : std::true_type { -}; -} // namespace framework - -} // namespace o2 - -/// Defining DataPointCompositeObject explicitly as copiable -namespace std -{ -template <> -struct is_trivially_copyable : std::true_type { -}; -} // namespace std +} // namespace o2::dcs #endif /* O2_DCS_DATAPOINT_COMPOSITE_OBJECT_H */ diff --git a/Detectors/DCS/include/DetectorsDCS/DataPointIdentifier.h b/Detectors/DCS/include/DetectorsDCS/DataPointIdentifier.h index 79b7d7cf886c7..faa12a3306d4f 100644 --- a/Detectors/DCS/include/DetectorsDCS/DataPointIdentifier.h +++ b/Detectors/DCS/include/DetectorsDCS/DataPointIdentifier.h @@ -31,9 +31,7 @@ #include "DetectorsDCS/GenericFunctions.h" #include "DetectorsDCS/DeliveryType.h" -namespace o2 -{ -namespace dcs +namespace o2::dcs { /** * DataPointIdentifier object is responsible for storing the alias and type @@ -41,19 +39,14 @@ namespace dcs */ class DataPointIdentifier final { - const uint64_t pt1; - const uint64_t pt2; - const uint64_t pt3; - const uint64_t pt4; - const uint64_t pt5; - const uint64_t pt6; - const uint64_t pt7; - const uint64_t pt8; // Contains the last 6 chars of alias and the type. - - DataPointIdentifier( - const uint64_t pt1, const uint64_t pt2, const uint64_t pt3, - const uint64_t pt4, const uint64_t pt5, const uint64_t pt6, - const uint64_t pt7, const uint64_t pt8) noexcept : pt1(pt1), pt2(pt2), pt3(pt3), pt4(pt4), pt5(pt5), pt6(pt6), pt7(pt7), pt8(pt8) {} + uint64_t pt1; + uint64_t pt2; + uint64_t pt3; + uint64_t pt4; + uint64_t pt5; + uint64_t pt6; + uint64_t pt7; + uint64_t pt8; // Contains the last 6 chars of alias and the type. public: /** @@ -85,15 +78,9 @@ class DataPointIdentifier final /** * 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(const DataPointIdentifier& src) noexcept = default; - DataPointIdentifier& operator=(const DataPointIdentifier& src) noexcept - { - if (&src != this) { - memcpy(this, &src, sizeof(DataPointIdentifier)); - } - return *this; - } + DataPointIdentifier& operator=(const DataPointIdentifier& src) noexcept = default; /** * This stati procedure fills the given DataPointIdentifier object with @@ -219,19 +206,7 @@ struct DPIDHash { return dpid.hash_code(); } }; -} // namespace dcs - -/// Defining DataPointIdentifier explicitly as messageable -namespace framework -{ -template -struct is_messageable; -template <> -struct is_messageable : std::true_type { -}; -} // namespace framework - -} // namespace o2 +} // namespace o2::dcs // specailized std::hash namespace std @@ -243,11 +218,6 @@ struct hash { return std::hash{}(dpid.hash_code()); } }; - -template <> -struct is_trivially_copyable : std::true_type { -}; - } // namespace std #endif /* O2_DCS_DATAPOINT_IDENTIFIER_H */ diff --git a/Detectors/DCS/src/DataPointCreator.cxx b/Detectors/DCS/src/DataPointCreator.cxx index 06b0321ad2c94..0bfb5bcd7d387 100644 --- a/Detectors/DCS/src/DataPointCreator.cxx +++ b/Detectors/DCS/src/DataPointCreator.cxx @@ -37,10 +37,9 @@ DataPointCompositeObject createDataPointCompositeObject(const std::string& alias 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(&tmp[0]), seconds, msec, flags, DeliveryType::DPVAL_FLOAT); + uint64_t tmp = 0; + memcpy(&tmp, &val, sizeof(val)); + return createDPCOM(alias, &tmp, seconds, msec, flags, DeliveryType::DPVAL_FLOAT); } template <> @@ -54,36 +53,38 @@ 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(&tmp), seconds, msec, flags, DeliveryType::DPVAL_UINT); + return createDPCOM(alias, &tmp, seconds, msec, flags, DeliveryType::DPVAL_UINT); } template <> DataPointCompositeObject createDataPointCompositeObject(const std::string& alias, long long val, uint32_t seconds, uint16_t msec, uint16_t flags) { uint64_t tmp{static_cast(val)}; - return createDPCOM(alias, reinterpret_cast(&tmp), seconds, msec, flags, DeliveryType::DPVAL_UINT); + return createDPCOM(alias, &tmp, seconds, msec, flags, DeliveryType::DPVAL_UINT); } template <> DataPointCompositeObject createDataPointCompositeObject(const std::string& alias, char val, uint32_t seconds, uint16_t msec, uint16_t flags) { - return createDPCOM(alias, reinterpret_cast(&val), seconds, msec, flags, DeliveryType::DPVAL_CHAR); + uint64_t tmp = 0; + memcpy(&tmp, &val, 1); + return createDPCOM(alias, &tmp, seconds, msec, flags, DeliveryType::DPVAL_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(&tmp), seconds, msec, flags, DeliveryType::DPVAL_BOOL); + return createDPCOM(alias, &tmp, seconds, msec, flags, DeliveryType::DPVAL_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(&str[0]), seconds, msec, flags, DeliveryType::DPVAL_STRING); + uint64_t tmp[N / sizeof(uint64_t)]; + strncpy((char*)tmp, val.c_str(), N); + return createDPCOM(alias, tmp, seconds, msec, flags, DeliveryType::DPVAL_STRING); } } // namespace o2::dcs diff --git a/Detectors/DCS/test/testDataPointTypes.cxx b/Detectors/DCS/test/testDataPointTypes.cxx index 491ebae1f5d00..dd7511f63217c 100644 --- a/Detectors/DCS/test/testDataPointTypes.cxx +++ b/Detectors/DCS/test/testDataPointTypes.cxx @@ -17,8 +17,6 @@ #include #include "DetectorsDCS/DataPointCompositeObject.h" #include "Framework/TypeTraits.h" -#include -#include #include #include @@ -26,7 +24,7 @@ typedef boost::mpl::list::value, true); + BOOST_CHECK_EQUAL(std::is_trivially_copyable_v, true); BOOST_CHECK_EQUAL(std::is_polymorphic::value, false); BOOST_CHECK_EQUAL(std::is_pointer::value, false); BOOST_CHECK_EQUAL(o2::framework::is_forced_non_messageable::value, false); diff --git a/Detectors/DCS/testWorkflow/src/DCSDataReplaySpec.cxx b/Detectors/DCS/testWorkflow/src/DCSDataReplaySpec.cxx index 783f6ae76e707..8dc003fc176f3 100644 --- a/Detectors/DCS/testWorkflow/src/DCSDataReplaySpec.cxx +++ b/Detectors/DCS/testWorkflow/src/DCSDataReplaySpec.cxx @@ -46,6 +46,10 @@ class DCSDataReplayer : public o2::framework::Task char mAlias[50]; uint64_t mMaxTF; uint64_t mTFs = 0; + int deltaTimeSendData = -1; + uint32_t startTime = -1; + uint32_t endTime = 0; + std::vector> dataIndicesPerTF; TTree mInputData; std::vector mDataPointHints; o2::header::DataDescription mDataDescription; @@ -59,6 +63,7 @@ void DCSDataReplayer::init(o2::framework::InitContext& ic) { mMaxTF = ic.options().get("max-timeframes"); mInputFileName = ic.options().get("input-file"); + deltaTimeSendData = ic.options().get("delta-time-send-data"); mInputData.ReadFile(mInputFileName.data(), "time/D:alias/C:value/D", ';'); mInputData.SetBranchAddress("time", &mTime); mInputData.SetBranchAddress("value", &mValue); @@ -73,16 +78,61 @@ void DCSDataReplayer::run(o2::framework::ProcessingContext& pc) LOG(info) << "Data generator reached TF " << tfid << ", stopping"; pc.services().get().endOfStream(); pc.services().get().readyToQuit(o2::framework::QuitRequest::Me); + return; } std::vector dpcoms; + for (Long64_t iEntry = 0; iEntry < mInputData.GetEntries(); ++iEntry) { - mInputData.GetEntry(iEntry); + int entryTree = iEntry; + + // load only releavant entries if requested + if (deltaTimeSendData > 0 && tfid > 2) { + + if (tfid - 1 >= dataIndicesPerTF.size()) { + LOGP(warning, "TF ID {} is larger than the number of TFs in dataIndicesPerTF: {}", tfid, dataIndicesPerTF.size()); + break; + } + + if (iEntry >= dataIndicesPerTF[tfid - 1].size()) { + break; + } else { + entryTree = dataIndicesPerTF[tfid - 1][iEntry]; + } + } + + mInputData.GetEntry(entryTree); const auto ultime = uint64_t(std::round(mTime * 1000)); const auto seconds = uint32_t(ultime / 1000); const auto msec = uint16_t(ultime % 1000); - - dpcoms.emplace_back(o2::dcs::createDataPointCompositeObject(mAlias, float(mValue), seconds, msec)); + if (deltaTimeSendData > 0) { + // send data in packages + if (tfid == 0) { + startTime = std::min(startTime, seconds); + endTime = std::max(endTime, seconds); + if (iEntry == mInputData.GetEntries() - 1) { + const int totalTFs = (endTime - startTime) / deltaTimeSendData + 1; + dataIndicesPerTF.resize(totalTFs); + LOGP(info, "Sending data from {} to {} with {} TFs", startTime, endTime, totalTFs); + } + } else { + if (tfid == 1) { + const int index = (seconds - startTime) / deltaTimeSendData; + dataIndicesPerTF[index].emplace_back(iEntry); + } + const uint64_t startTimeTF = startTime + (tfid - 1) * deltaTimeSendData; + const uint64_t endTimeTF = startTimeTF + deltaTimeSendData; + if (seconds >= startTimeTF && seconds < endTimeTF) { + dpcoms.emplace_back(o2::dcs::createDataPointCompositeObject(mAlias, float(mValue), seconds, msec)); + // check if all data has been processed + if (seconds == endTime) { + mMaxTF = tfid; + } + } + } + } else { + dpcoms.emplace_back(o2::dcs::createDataPointCompositeObject(mAlias, float(mValue), seconds, msec)); + } } // auto dpcoms = generate(mDataPointHints, fraction, tfid); @@ -113,6 +163,7 @@ o2::framework::DataProcessorSpec getDCSDataReplaySpec(std::vector #include -#include #include #include #include "Rtypes.h" @@ -277,9 +276,10 @@ class ClusterFactory /// \brief Look to cell neighbourhood and reject if it seems exotic /// \param towerId: tower ID of cell with largest energy fraction in cluster /// \param ecell: energy of the cell with largest energy fraction in cluster - /// \param exoticTime time of the cell with largest energy fraction in cluster + /// \param exoticTime: time of the cell with largest energy fraction in cluster + /// \param fCross: exoticity parameter (1-E_cross/E_cell^max) will be caluclated for this check /// \return bool true if cell is found exotic - bool isExoticCell(short towerId, float ecell, float const exoticTime) const; + bool isExoticCell(short towerId, float ecell, float const exoticTime, float& fCross) const; /// \brief Calculate the energy in the cross around the energy of a given cell. /// \param absID: controlled cell absolute ID number @@ -335,7 +335,7 @@ class ClusterFactory bool getUseWeightExotic() const { return mUseWeightExotic; } void setUseWeightExotic(float useWeightExotic) { mUseWeightExotic = useWeightExotic; } - void setContainer(gsl::span clusterContainer, gsl::span cellContainer, gsl::span indicesContainer, std::optional> cellLabelContainer = std::nullopt) + void setContainer(gsl::span clusterContainer, gsl::span cellContainer, gsl::span indicesContainer, gsl::span cellLabelContainer = {}) { mClustersContainer = clusterContainer; mInputsContainer = cellContainer; @@ -343,8 +343,8 @@ class ClusterFactory if (!getLookUpInit()) { setLookUpTable(); } - if (cellLabelContainer) { - mCellLabelContainer = cellLabelContainer.value(); + if (!cellLabelContainer.empty()) { + mCellLabelContainer = cellLabelContainer; } } @@ -401,6 +401,10 @@ class ClusterFactory /// in cell units void evalElipsAxis(gsl::span inputsIndices, AnalysisCluster& clusterAnalysis) const; + /// + /// Calculate the number of local maxima in the cluster + void evalNExMax(gsl::span inputsIndices, AnalysisCluster& clusterAnalysis) const; + /// /// Time is set to the time of the digit with the maximum energy void evalTime(gsl::span inputsIndices, AnalysisCluster& clusterAnalysis) const; diff --git a/Detectors/EMCAL/base/include/EMCALBase/Geometry.h b/Detectors/EMCAL/base/include/EMCALBase/Geometry.h index 04dcaa3b802de..d07f42689bf7a 100644 --- a/Detectors/EMCAL/base/include/EMCALBase/Geometry.h +++ b/Detectors/EMCAL/base/include/EMCALBase/Geometry.h @@ -12,14 +12,16 @@ #ifndef ALICEO2_EMCAL_GEOMETRY_H_ #define ALICEO2_EMCAL_GEOMETRY_H_ -#include +#include #include +#include #include #include #include +#include #include -#include +#include #include #include @@ -57,7 +59,7 @@ class Geometry /// | EMCAL_COMPLETE12SMV1_DCAL | Full EMCAL, 10 DCAL Supermodules (not used in practice) | /// | EMCAL_COMPLETE12SMV1_DCAL_8SM | Full EMCAL, 8 DCAL Supermodules (run2) | /// | EMCAL_COMPLETE12SMV1_DCAL_DEV | Full EMCAL, DCAL development geometry (not used) | - Geometry(const std::string_view name, const std::string_view mcname = "", const std::string_view mctitle = ""); + explicit Geometry(const std::string_view name, const std::string_view mcname = "", const std::string_view mctitle = ""); /// \brief Copy constructor. Geometry(const Geometry& geom); @@ -427,6 +429,14 @@ class Geometry /// \return Position (0 - phi, 1 - eta) of the cell inside teh supermodule std::tuple GetCellPhiEtaIndexInSModule(int supermoduleID, int moduleID, int phiInModule, int etaInModule) const; + /// \brief Get topological row and column of cell in SM (same as for clusteriser with artifical gaps) + /// \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 tuple with (row, column) of the cell, which is global numbering scheme + std::tuple GetTopologicalRowColumn(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 /// \param iphi row/phi cell index, modified for DCal @@ -513,6 +523,14 @@ class Geometry /// \return col std::tuple getOnlineID(int towerID); + /// \brief Check if 2 cells belong to the same T-Card + /// \param absId1: Reference absId cell + /// \param absId2: Cross checked cell absId + /// \return true if belong to same TCard else false + /// \return rowDiff: Distance in rows + /// \return colDiff: Distance in columns + std::tuple areAbsIDsFromSameTCard(int absId1, int absId2) const; + /// \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 @@ -564,6 +582,11 @@ class Geometry /// void SetMisalMatrix(const TGeoHMatrix* m, Int_t smod) const; + /// + /// Method to set shift-rotational matrixes from CCDB + /// + void SetMisalMatrixFromCcdb(const char* path = "Users/m/mhemmer/EMCAL/Config/GeometryAligned", int timestamp = 10000) const; + /// /// Transform clusters cell position into global with alternative method, taking into account the depth calculation. /// Input are: diff --git a/Detectors/EMCAL/base/src/ClusterFactory.cxx b/Detectors/EMCAL/base/src/ClusterFactory.cxx index 0c801de615487..1752e5c0e98ee 100644 --- a/Detectors/EMCAL/base/src/ClusterFactory.cxx +++ b/Detectors/EMCAL/base/src/ClusterFactory.cxx @@ -73,8 +73,11 @@ o2::emcal::AnalysisCluster ClusterFactory::buildCluster(int clusterIn float exoticTime = mInputsContainer[inputIndMax].getTimeStamp(); + float fCross = 0.; + try { - clusterAnalysis.setIsExotic(isExoticCell(towerId, inputEnergyMax, exoticTime)); + clusterAnalysis.setIsExotic(isExoticCell(towerId, inputEnergyMax, exoticTime, fCross)); + clusterAnalysis.setFCross(fCross); } catch (UninitLookUpTableException& e) { LOG(error) << e.what(); } @@ -117,6 +120,9 @@ o2::emcal::AnalysisCluster ClusterFactory::buildCluster(int clusterIn evalElipsAxis(inputsIndices, clusterAnalysis); evalDispersion(inputsIndices, clusterAnalysis); + // evaluate number of local maxima + evalNExMax(inputsIndices, clusterAnalysis); + evalCoreEnergy(inputsIndices, clusterAnalysis); evalTime(inputsIndices, clusterAnalysis); @@ -253,7 +259,7 @@ void ClusterFactory::evalLocalPosition(gsl::span inputsInd clRmsXYZ[i] += (w * xyzi[i] * xyzi[i]); } } // w > 0 - } // dig loop + } // dig loop // cout << " wtot " << wtot << endl; @@ -486,6 +492,64 @@ void ClusterFactory::evalCoreEnergy(gsl::span inputsIndice clusterAnalysis.setCoreEnergy(coreEnergy); } +/// +/// Calculate the number of local maxima in the cluster +//____________________________________________________________________________ +template +void ClusterFactory::evalNExMax(gsl::span inputsIndices, AnalysisCluster& clusterAnalysis) const +{ + // Pre-compute cell indices and energies for all cells in cluster to avoid multiple expensive geometry lookups + const size_t n = inputsIndices.size(); + std::vector rows; + std::vector columns; + std::vector energies; + + rows.reserve(n); + columns.reserve(n); + energies.reserve(n); + + for (auto iInput : inputsIndices) { + auto [nSupMod, nModule, nIphi, nIeta] = mGeomPtr->GetCellIndex(mInputsContainer[iInput].getTower()); + + // get a nice topological indexing that is done in exactly the same way as used by the clusterizer + // this way we can handle the shared cluster cases correctly + const auto [row, column] = mGeomPtr->GetTopologicalRowColumn(nSupMod, nModule, nIphi, nIeta); + + rows.push_back(row); + columns.push_back(column); + energies.push_back(mInputsContainer[iInput].getEnergy()); + } + + // Now find local maxima using pre-computed data + int nExMax = 0; + for (size_t i = 0; i < n; i++) { + // this cell is assumed to be local maximum unless we find a higher energy cell in the neighborhood + bool isExMax = true; + + // loop over all other cells in cluster + for (size_t j = 0; j < n; j++) { + if (i == j) { + continue; + } + + // adjacent cell is any cell with adjacent phi or eta index + if (std::abs(rows[i] - rows[j]) <= 1 && + std::abs(columns[i] - columns[j]) <= 1) { + + // if there is a cell with higher energy than the current cell, it is not a local maximum + if (energies[j] > energies[i]) { + isExMax = false; + break; + } + } + } + if (isExMax) { + nExMax++; + } + } + clusterAnalysis.setNExMax(nExMax); +} + /// /// Calculates the axis of the shower ellipsoid in eta and phi /// in cell units @@ -600,7 +664,7 @@ std::tuple ClusterFactory::getMaximalEnergyI /// Look to cell neighbourhood and reject if it seems exotic //____________________________________________________________________________ template -bool ClusterFactory::isExoticCell(short towerId, float ecell, float const exoticTime) const +bool ClusterFactory::isExoticCell(short towerId, float ecell, float const exoticTime, float& fCross) const { if (ecell < mExoticCellMinAmplitude) { return false; // do not reject low energy cells @@ -612,8 +676,9 @@ bool ClusterFactory::isExoticCell(short towerId, float ecell, float c } float eCross = getECross(towerId, ecell, exoticTime); + fCross = 1.f - eCross / ecell; - if (1 - eCross / ecell > mExoticCellFraction) { + if (fCross > mExoticCellFraction) { LOG(debug) << "EXOTIC CELL id " << towerId << ", eCell " << ecell << ", eCross " << eCross << ", 1-eCross/eCell " << 1 - eCross / ecell; return true; } diff --git a/Detectors/EMCAL/base/src/Geometry.cxx b/Detectors/EMCAL/base/src/Geometry.cxx index 920dc24823e83..3707e22f2da57 100644 --- a/Detectors/EMCAL/base/src/Geometry.cxx +++ b/Detectors/EMCAL/base/src/Geometry.cxx @@ -8,17 +8,40 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include "EMCALBase/Geometry.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include #include +#include +#include +#include +#include +#include +#include #include #include #include -#include -#include - -#include "EMCALBase/Geometry.h" +#include "DataFormatsEMCAL/Constants.h" +#include "EMCALBase/GeometryBase.h" +#include "CCDB/CcdbApi.h" #include "EMCALBase/ShishKebabTrd1Module.h" +#include "GPUROOTCartesianFwd.h" #include @@ -1080,6 +1103,30 @@ std::tuple Geometry::GetCellPhiEtaIndexInSModule(int supermoduleID, in return std::make_tuple(phiInSupermodule, etaInSupermodule); } +std::tuple Geometry::GetTopologicalRowColumn(int supermoduleID, int moduleID, int phiInModule, int etaInModule) const +{ + auto [iphi, ieta] = GetCellPhiEtaIndexInSModule(supermoduleID, moduleID, phiInModule, etaInModule); + int row = iphi; + int column = ieta; + + // Add shifts wrt. supermodule and type of calorimeter + // NOTE: + // * Rows (phi) are arranged that one space is left empty between supermodules in phi + // This is due to the physical gap that forbids clustering + // * For DCAL, there is an additional empty column between two supermodules in eta + // Again, this is to account for the gap in DCAL + + row += supermoduleID / 2 * (24 + 1); + // In DCAL, leave a gap between two SMs with same phi + if (!IsDCALSM(supermoduleID)) { // EMCAL + column += supermoduleID % 2 * 48; + } else { + column += supermoduleID % 2 * (48 + 1); + } + + return std::make_tuple(static_cast(row), static_cast(column)); +} + std::tuple Geometry::ShiftOnlineToOfflineCellIndexes(Int_t supermoduleID, Int_t iphi, Int_t ieta) const { if (supermoduleID == 13 || supermoduleID == 15 || supermoduleID == 17) { @@ -1557,6 +1604,7 @@ const TGeoHMatrix* Geometry::GetMatrixForSuperModule(Int_t smod) const if (!SMODULEMATRIX[smod]) { if (gGeoManager) { + LOG(info) << "Loading EMCAL misalignment matrix for SM " << smod << " from GeoManager."; SetMisalMatrix(GetMatrixForSuperModuleFromGeoManager(smod), smod); } else { LOG(fatal) << "Cannot find EMCAL misalignment matrices! Recover them either: \n" @@ -1762,6 +1810,25 @@ void Geometry::SetMisalMatrix(const TGeoHMatrix* m, Int_t smod) const } } +void Geometry::SetMisalMatrixFromCcdb(const char* path, int timestamp) const +{ + LOG(info) << "Using CCDB to obtain EMCal alignment."; + o2::ccdb::CcdbApi api; + std::map metadata; // can be empty + api.init("http://alice-ccdb.cern.ch"); + TObjArray* matrices = api.retrieveFromTFileAny(path, metadata, timestamp); + + for (int iSM = 0; iSM < mNumberOfSuperModules; ++iSM) { + TGeoHMatrix* mat = reinterpret_cast(matrices->At(iSM)); + if (mat) { + + SetMisalMatrix(mat, iSM); + } else { + LOG(info) << "Could not obtain Alignment Matrix for SM " << iSM; + } + } +} + Bool_t Geometry::IsDCALSM(Int_t iSupMod) const { if (mEMCSMSystem[iSupMod] == DCAL_STANDARD || mEMCSMSystem[iSupMod] == DCAL_EXT) { @@ -1834,3 +1901,44 @@ std::tuple Geometry::getOnlineID(int towerID) return std::make_tuple(supermoduleID * 2 + ddlInSupermoudel, row, col); } + +std::tuple Geometry::areAbsIDsFromSameTCard(int absId1, int absId2) const +{ + + int rowDiff = -100; + int colDiff = -100; + + if (absId1 == absId2) { + return {false, rowDiff, colDiff}; + } + + // Check if in same SM, if not for sure not same TCard + const int sm1 = GetSuperModuleNumber(absId1); + const int sm2 = GetSuperModuleNumber(absId2); + if (sm1 != sm2) { + return {false, rowDiff, colDiff}; + } + + // Get the column and row of each absId + const auto [_, iTower1, iIphi1, iIeta1] = GetCellIndex(absId1); + const auto [row1, col1] = GetCellPhiEtaIndexInSModule(sm1, iTower1, iIphi1, iIeta1); + + const auto [__, iTower2, iIphi2, iIeta2] = GetCellIndex(absId2); + const auto [row2, col2] = GetCellPhiEtaIndexInSModule(sm2, iTower2, iIphi2, iIeta2); + + // Define corner of TCard for absId1 + const int tcardRow0 = row1 - row1 % 8; + const int tcardCol0 = col1 - col1 % 2; + + // Difference of absId2 from corner of absId1's TCard + const int rowOffset = row2 - tcardRow0; + const int colOffset = col2 - tcardCol0; + + // Differences between the two cells directly + rowDiff = row1 - row2; + colDiff = col1 - col2; + + const bool sameTCard = (rowOffset >= 0 && rowOffset < 8 && + colOffset >= 0 && colOffset < 2); + return {sameTCard, rowDiff, colDiff}; +} diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/CellRecalibrator.h b/Detectors/EMCAL/calib/include/EMCALCalib/CellRecalibrator.h index 571b43d05ef08..ea8a0445bbe5e 100644 --- a/Detectors/EMCAL/calib/include/EMCALCalib/CellRecalibrator.h +++ b/Detectors/EMCAL/calib/include/EMCALCalib/CellRecalibrator.h @@ -62,7 +62,7 @@ class CellRecalibrator public: /// \class CellTypeException /// \brief Handling of invalid cell types in calibration - class CellTypeException : public std::exception + class CellTypeException final : public std::exception { public: /// \brief Constructor @@ -73,7 +73,7 @@ class CellRecalibrator /// \brief Get error message of the exception /// \return Error message - const char* what() const noexcept final + [[nodiscard]] char const* what() const noexcept final { return "Only possible to calibrate cells of type high gain or low gain"; } @@ -208,4 +208,4 @@ std::ostream& operator<<(std::ostream& in, const CellRecalibrator& calib); } // namespace o2 -#endif // !ALCEO2_EMCAL_CELLRECALIBRATOR_H \ No newline at end of file +#endif // !ALCEO2_EMCAL_CELLRECALIBRATOR_H diff --git a/Detectors/EMCAL/calibration/CMakeLists.txt b/Detectors/EMCAL/calibration/CMakeLists.txt index 68c8fd1eb69c7..7fec9fcef0f93 100644 --- a/Detectors/EMCAL/calibration/CMakeLists.txt +++ b/Detectors/EMCAL/calibration/CMakeLists.txt @@ -20,6 +20,7 @@ o2_add_library(EMCALCalibration src/PedestalCalibDevice.cxx src/PedestalProcessorDevice.cxx src/PedestalProcessorData.cxx + src/EMCALTempCalibExtractor.cxx PUBLIC_LINK_LIBRARIES O2::CCDB O2::EMCALBase O2::EMCALCalib O2::EMCALReconstruction @@ -46,6 +47,7 @@ o2_target_root_dictionary(EMCALCalibration include/EMCALCalibration/EMCDCSProcessor.h include/EMCALCalibration/EMCALPedestalHelper.h include/EMCALCalibration/PedestalProcessorData.h + include/EMCALCalibration/EMCALTempCalibExtractor.h LINKDEF src/EMCALCalibrationLinkDef.h) o2_add_executable(emcal-channel-calib-workflow diff --git a/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALTempCalibExtractor.h b/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALTempCalibExtractor.h new file mode 100644 index 0000000000000..5dbaec4c933f8 --- /dev/null +++ b/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALTempCalibExtractor.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. + +/// \class EMCALTempCalibExtractor +/// \brief Calculate gain correction factors based on the temperature and the cell-by-cell temperature dependent correction factors (slope and intercept) +/// \author Joshua König +/// \ingroup EMCALCalib +/// \since June 30, 2025 + +#ifndef EMCALTEMPCALIBEXTRACTOR_H_ +#define EMCALTEMPCALIBEXTRACTOR_H_ + +#include +#include +#include +#include "CCDB/BasicCCDBManager.h" +#include "EMCALCalib/ElmbData.h" +#include "EMCALCalib/TempCalibrationParams.h" +#include "EMCALBase/Geometry.h" + +namespace o2 +{ +namespace emcal +{ + +class EMCALTempCalibExtractor +{ + + public: + /// \brief Constructor + EMCALTempCalibExtractor() + { + LOG(info) << "initialized EMCALTempCalibExtractor"; + try { + // Try to access geometry initialized ountside + mGeometry = o2::emcal::Geometry::GetInstance(); + } catch (o2::emcal::GeometryNotInitializedException& e) { + mGeometry = o2::emcal::Geometry::GetInstanceFromRunNumber(300000); // fallback option + } + }; + /// \brief Destructor + ~EMCALTempCalibExtractor() = default; + + /// \brief Initialize temperature data and slope for each cell from the ccdb + /// \param path path to the slope data + /// \param timestamp timestamp for the ccdb objects or runnumber (will detect automatically if its a runnumber and convert it) + void InitializeFromCCDB(std::string path, uint64_t timestamp); + + /// \brief get average temperature in a supermodule + /// \param iSM SM number + /// \param ElmbData object where temperature sensor values are stored + /// \return average temperature in a supermodule + float getTemperatureForSM(const unsigned short iSM, o2::emcal::ElmbData* ElmbData) const; + + /// \brief get gain calibration factor depending on the temperature and the slope of the cell + /// \param cellID cell ID + /// \return gain calibration factor + float getGainCalibFactor(const unsigned short cellID) const; + + /// \brief set temperature range in which sensor ddata is assumed to be good + /// \param low lower temperature + /// \param high upper temperature + void setAcceptedEnergyRange(float low, float high); + + /// \brief set if median (true) or mean (false) should be used for averaging of the temperature in a SM + void setUseMedian(const bool tmp) { mUseMedian = tmp; } + + /// \brief get sensor IDs for a specific supermodule + /// \param iSM SM number + /// \return vector of sensor IDs + std::vector getSensorsForSM(const unsigned short iSM) const; + + private: + static constexpr unsigned short mNCells = 17664; ///< Number of EMCal cells + std::array mGainCalibFactors; ///< gain calibration factors that are calculated based on the temperature and the slopes for each cell + o2::emcal::Geometry* mGeometry; ///< pointer to the EMCal geometry + std::array mAcceptedTempRange = {15., 30.}; ///< Temperature range where sensors are believed to send good data. Temperatures outside this range will be rejected + bool mUseMedian = true; /// switch to decide if temperature within a SM should be calculated as the mean or the median of the individual sensor data +}; + +} // namespace emcal + +} // namespace o2 + +#endif \ No newline at end of file diff --git a/Detectors/EMCAL/calibration/src/EMCALTempCalibExtractor.cxx b/Detectors/EMCAL/calibration/src/EMCALTempCalibExtractor.cxx new file mode 100644 index 0000000000000..02e25696f161d --- /dev/null +++ b/Detectors/EMCAL/calibration/src/EMCALTempCalibExtractor.cxx @@ -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. + +#include "EMCALCalibration/EMCALTempCalibExtractor.h" +#include "EMCALCalib/CalibDB.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" +#include + +namespace o2 +{ +namespace emcal +{ + +void EMCALTempCalibExtractor::InitializeFromCCDB(std::string path, uint64_t timestamp) +{ + + auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance(); + uint64_t maxRunNr = 1000000; + if (timestamp < maxRunNr) { + LOG(info) << "assuming input is run " << timestamp << " will convert it to timstamp"; + auto [sor, eor] = ccdbMgr.getRunDuration(timestamp); + uint64_t sixtySec = 60000; + timestamp = eor - sixtySec; // safety margin of 1min at EOR + LOG(info) << "set timestamp to " << timestamp; + } + + o2::emcal::CalibDB calibdb("http://alice-ccdb.cern.ch"); + std::map metadata; + auto tempSensorData = calibdb.readTemperatureSensorData(timestamp, metadata); + + // also obtain cell dependent correction factors + TempCalibrationParams* params = ccdbMgr.getForTimeStamp(path, timestamp); + + std::map mapSMTemperature; + for (unsigned short i = 0; i < mNCells; ++i) { + const unsigned short iSM = mGeometry->GetSuperModuleNumber(i); + if (mapSMTemperature.count(iSM) == 0) { + mapSMTemperature[iSM] = getTemperatureForSM(iSM, tempSensorData); + } + float corrFac = params->getTempCalibParamA0(i) + params->getTempCalibParamSlope(i) * mapSMTemperature[iSM]; + mGainCalibFactors[i] = corrFac; + } +} + +float EMCALTempCalibExtractor::getTemperatureForSM(const unsigned short iSM, o2::emcal::ElmbData* ElmbData) const +{ + if (iSM < 0 || iSM > 20) { + LOG(error) << "SM " << iSM << "does not exist!"; // could be replaced with a proper exception + return 0.; + } + std::vector vecSensorID = getSensorsForSM(iSM); + + // Obtain temperature for these sensors + std::vector vecTemperature; + for (const auto& iSensor : vecSensorID) { + float temp = ElmbData->getMean(iSensor); + if (temp < mAcceptedTempRange[0] || temp > mAcceptedTempRange[1]) { + continue; + } + vecTemperature.push_back(temp); + } + + const unsigned int nEntries = vecTemperature.size(); + if (nEntries == 0) { + LOG(warning) << "No sensor data between " << mAcceptedTempRange[0] << " and " << mAcceptedTempRange[1] << "degree found... for SM " << iSM << " Setting to default 20 degree"; + return 20.; // + } + + // get median energy + float tempSM = 0.; + if (mUseMedian) { + std::sort(vecTemperature.begin(), vecTemperature.end()); + if (nEntries % 2 == 0) { + // even number of elements: average the two middle ones + tempSM = (vecTemperature[nEntries / 2 - 1] + vecTemperature[nEntries / 2]) / 2.0; + } else { + // odd number of elements: return the middle one + tempSM = vecTemperature[nEntries / 2]; + } + } else { // use Mean temperature + float sum = std::accumulate(vecTemperature.begin(), vecTemperature.end(), 0.0); + tempSM = sum / vecTemperature.size(); + } + return tempSM; +} + +float EMCALTempCalibExtractor::getGainCalibFactor(const unsigned short cellID) const +{ + if (cellID >= mNCells) { + LOG(error) << "cell ID" << cellID << " does not exist"; + return 1.; + } + return mGainCalibFactors[cellID]; +} + +std::vector EMCALTempCalibExtractor::getSensorsForSM(const unsigned short iSM) const +{ + unsigned short nSensors = 8; + if (iSM == 10 || iSM == 11 || iSM == 18 || iSM == 19) { // 1/3 SM of EMCal only have 4 sensors + nSensors = 4; + } + + std::vector vecSensorID; + for (unsigned short iELMBSensor = iSM * 8; iELMBSensor < iSM * 8 + nSensors; iELMBSensor++) { + vecSensorID.push_back(iELMBSensor); + } + return vecSensorID; +} + +void EMCALTempCalibExtractor::setAcceptedEnergyRange(float low, float high) +{ + mAcceptedTempRange[0] = low; + mAcceptedTempRange[1] = high; +} + +} // namespace emcal + +} // namespace o2 \ No newline at end of file diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h index 1617a9f1a7d54..706b9bf8138a6 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h @@ -32,10 +32,10 @@ namespace o2 namespace emcal { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::EMC) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::EMC, 1.f, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode data to buffer with CTF diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/TRUDataHandler.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/TRUDataHandler.h index 811faf13a05ff..ea9820563dee6 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/TRUDataHandler.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/TRUDataHandler.h @@ -13,6 +13,7 @@ #include #include +#include #include #include #include diff --git a/Detectors/EMCAL/reconstruction/run/rawReaderTRUDigits.cxx b/Detectors/EMCAL/reconstruction/run/rawReaderTRUDigits.cxx deleted file mode 100644 index 6fc119dc69521..0000000000000 --- a/Detectors/EMCAL/reconstruction/run/rawReaderTRUDigits.cxx +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file rawReaderFileNew.cxx -/// \author Markus Fasel , Oak Ridge National Laboratory - -#include -#include - -#include - -#include "DetectorsRaw/RawFileReader.h" -#include "DetectorsRaw/RDHUtils.h" -#include "EMCALBase/Mapper.h" -#include "EMCALBase/TriggerMappingV2.h" -#include "EMCALReconstruction/AltroDecoder.h" -#include "EMCALReconstruction/RawReaderMemory.h" -#include - -namespace bpo = boost::program_options; -// using namespace o2::emcal; - -int main(int argc, char** argv) -{ - bpo::variables_map vm; - bpo::options_description opt_general("Usage:\n " + std::string(argv[0]) + - " \n" - " Tool will decode the DDLx data for EMCAL 0\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()->default_value(0), "Select verbosity level [0 = no output]"); - add_option("version", "Print version information"); - add_option("input-file,i", bpo::value()->required(), "Specifies input file."); - add_option("debug,d", bpo::value()->default_value(0), "Select debug output level [0 = no debug output]"); - - 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); - } - - if (vm.count("version")) { - // std::cout << GitInfo(); - 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); - } - - auto rawfilename = vm["input-file"].as(); - - o2::raw::RawFileReader reader; - reader.setDefaultDataOrigin(o2::header::gDataOriginEMC); - reader.setDefaultDataDescription(o2::header::gDataDescriptionRawData); - reader.setDefaultReadoutCardType(o2::raw::RawFileReader::RORC); - reader.addFile(rawfilename); - reader.init(); - - o2::emcal::MappingHandler mapper; - o2::emcal::TriggerMappingV2 triggermapping; - - std::unique_ptr treefile(TFile::Open("trudata.root", "RECREATE")); - TTree trudata("trudata", "Tree with TRU data"); - // branches in tree - struct collisiontrigger { - unsigned long bc; - unsigned long orbit; - } mycollision; - int absFastOR; - int starttime; - std::vector timesamples; - tree->Branch(&mycollision, "collisiontrigger", "bc,orbit/l"); - tree->Branch(&starttime, "starttime", "starttime/i"); - tree->Branch(×amples, "timesamples", ""); // @todo check how to write std::vector to tree; - - while (1) { - int tfID = reader.getNextTFToRead(); - if (tfID >= reader.getNTimeFrames()) { - LOG(info) << "nothing left to read after " << tfID << " TFs read"; - break; - } - std::vector dataBuffer; // where to put extracted data - 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(); - auto rdh = parser.getRawHeader(); - auto ddl = o2::raw::RDHUtils::getFEEID(parser.getRawHeader()); - // Exclude STU DDLs - if (ddl >= 40) { - continue; - } - - mycollision.bc = o2::raw::RDHUtils::getTriggerBC(rdh); - mycollision.orbit = o2::raw::RDHUtils::getTriggerOrbit(rdh); - - o2::emcal::AltroDecoder decoder(parser); - decoder.decode(); - auto& ddlmapping = mapper.getMappingForDDL(ddl); - - std::cout << decoder.getRCUTrailer() << std::endl; - for (auto& chan : decoder.getChannels()) { - if (ddlmapping.getChannelType(chan.getHardwareAddress) != o2::emcal::ChannelType_t::TRU) { - continue; - } - std::cout << "Hw address: " << chan.getHardwareAddress() << std::endl; - // Get absolute FastOR index - this will tell us where on the EMCAL surface the FastOR is - // TRU index is encoded in column, needs to be converted to an absoluted FastOR ID via the - // trigger mapping. The absoluted FastOR ID can be connected via the geometry to tower IDs - // from the FEC data. - // we are only interested in the FastORs for now, skip patches starting from 96 - auto fastorInTRU = ddlmapping.getColumn(chan.getHardwareAddress()); - if (fastorInTRU >= 96) { - // indices starting from 96 encode patches, not FastORs - continue; - } - auto truindex = triggermapping.getTRUIndexFromOnlineHardareAddree(chan.getHardwareAddress(), ddl, ddl / 2); - auto absFastOrID = triggermapping.getAbsFastORIndexFromIndexInTRU(truindex, fastorInTRU); - - for (auto& bunch : chan.getBunches()) { - std::cout << "BunchLength: " << int(bunch.getBunchLength()) << std::endl; - auto adcs = bunch.getADC(); - int time = bunch.getStartTime(); - starttime = time; - timesamples.clear(); - timesamples.resize(adcs.size()); - std::copy(adcs.begin(), adcs.end(), timesamples.begin()); - trudata.Fill(); - for (int i = adcs.size() - 1; i >= 0; i--) { - std::cout << "Timebin " << time << ", ADC " << adcs[i] << std::endl; - time--; - } - } - } - } - } - reader.setNextTFToRead(++tfID); - } -} \ No newline at end of file diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyDecoderSpec.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyDecoderSpec.h index 0215e0ae65e43..9cc5ba7887473 100644 --- a/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyDecoderSpec.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyDecoderSpec.h @@ -28,7 +28,7 @@ namespace emcal class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity, unsigned int sspecOut); + EntropyDecoderSpec(int verbosity, unsigned int sspecOut, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -42,7 +42,7 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspecInp, unsigned int sspecOut = 0); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspecInp, unsigned int sspecOut = 0, const std::string& ctfdictOpt = "none"); } // namespace emcal } // namespace o2 diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyEncoderSpec.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyEncoderSpec.h index cdfb342e7ff11..df502beef30df 100644 --- a/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyEncoderSpec.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyEncoderSpec.h @@ -28,7 +28,7 @@ namespace emcal class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR); + EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -42,7 +42,7 @@ class EntropyEncoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); } // namespace emcal } // namespace o2 diff --git a/Detectors/EMCAL/workflow/src/EntropyDecoderSpec.cxx b/Detectors/EMCAL/workflow/src/EntropyDecoderSpec.cxx index 700f468e9e73d..ecc0e45492bea 100644 --- a/Detectors/EMCAL/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/EMCAL/workflow/src/EntropyDecoderSpec.cxx @@ -24,8 +24,7 @@ namespace o2 { namespace emcal { - -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, unsigned int sspecOut) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder), mSSpecOut(sspecOut) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, unsigned int sspecOut, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt), mSSpecOut(sspecOut) { mTimer.Stop(); mTimer.Reset(); @@ -74,7 +73,7 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspecInp, unsigned int sspecOut) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspecInp, unsigned int sspecOut, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"triggers"}, "EMC", "CELLSTRGR", sspecOut, Lifetime::Timeframe}, @@ -83,17 +82,18 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspecInp, un std::vector inputs; inputs.emplace_back("ctf_EMC", "EMC", "CTFDATA", sspecInp, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_EMC", "EMC", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("EMC/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_EMC", "EMC", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("EMC/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ "emcal-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity, sspecOut)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(verbosity, sspecOut, ctfdictOpt)}, + Options{{"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace emcal } // namespace o2 diff --git a/Detectors/EMCAL/workflow/src/EntropyEncoderSpec.cxx b/Detectors/EMCAL/workflow/src/EntropyEncoderSpec.cxx index 773c4c65fc9fe..2928a71a167bc 100644 --- a/Detectors/EMCAL/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/EMCAL/workflow/src/EntropyEncoderSpec.cxx @@ -25,8 +25,7 @@ namespace o2 { namespace emcal { - -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR) { mTimer.Stop(); mTimer.Reset(); @@ -71,12 +70,15 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("triggers", "EMC", "CELLSTRGR", 0, Lifetime::Timeframe); inputs.emplace_back("cells", "EMC", "CELLS", 0, Lifetime::Timeframe); - inputs.emplace_back("ctfdict", "EMC", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("EMC/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "EMC", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("EMC/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -85,14 +87,11 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR) inputs, Outputs{{"EMC", "CTFDATA", 0, Lifetime::Timeframe}, {{"ctfrep"}, "EMC", "CTFENCREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR)}, - Options{ - {"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, - {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, - {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, + {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, + {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace emcal } // namespace o2 diff --git a/Detectors/EMCAL/workflow/src/StandaloneAODProducerSpec.cxx b/Detectors/EMCAL/workflow/src/StandaloneAODProducerSpec.cxx index 73987ce6d1c1b..227fc373bf20c 100644 --- a/Detectors/EMCAL/workflow/src/StandaloneAODProducerSpec.cxx +++ b/Detectors/EMCAL/workflow/src/StandaloneAODProducerSpec.cxx @@ -17,7 +17,6 @@ #include "Framework/InputRecordWalker.h" #include "Framework/Logger.h" #include "Framework/TableBuilder.h" -#include "Framework/TableTreeHelpers.h" #include "MathUtils/Utils.h" using namespace o2::framework; @@ -105,7 +104,7 @@ void StandaloneAODProducerSpec::run(ProcessingContext& pc) o2::math_utils::detail::truncateFloatFraction(cell.getTimeStamp(), mCaloTime), cell.getType(), 1); // hard coded for emcal (-1 would be undefined, 0 phos) - } // end of cell loop + } // end of cell loop // filled only with BCID, rest dummy for no2 caloCellsTRGTableCursor(0, diff --git a/Detectors/EMCAL/workflow/src/entropy-encoder-workflow.cxx b/Detectors/EMCAL/workflow/src/entropy-encoder-workflow.cxx index e6af02fa10d49..d5264aabc0566 100644 --- a/Detectors/EMCAL/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/EMCAL/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "none", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -37,6 +38,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::emcal::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"))); + wf.emplace_back(o2::emcal::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/FIT/FDD/base/src/Geometry.cxx b/Detectors/FIT/FDD/base/src/Geometry.cxx index 441a30fdda44f..149c086f4fc81 100644 --- a/Detectors/FIT/FDD/base/src/Geometry.cxx +++ b/Detectors/FIT/FDD/base/src/Geometry.cxx @@ -152,7 +152,7 @@ void Geometry::buildGeometry() if (!vCaveRB24) { LOG(fatal) << "Could not find the top volume for A-side"; } - const Float_t kPosFDA = 1696.67 - 1313.347; // z-center of assembly (cm) + const Float_t kPosFDA = 1696.67 - 1313.347 - 75.; // z-center of assembly (cm) vCaveRB24->AddNode(vFDAarray, 1, new TGeoTranslation(0., 0., kPosFDA - kFDACelldz / 2. - 0.1)); vCaveRB24->AddNode(vFDAarray, 2, new TGeoTranslation(0., 0., kPosFDA + kFDACelldz / 2. + 0.1)); diff --git a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/CTFCoder.h b/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/CTFCoder.h index dc11174908c75..24649f73a4ca3 100644 --- a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/CTFCoder.h +++ b/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/CTFCoder.h @@ -33,10 +33,10 @@ namespace o2 namespace fdd { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::FDD) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::FDD, 1.f, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode digits to buffer with CTF @@ -165,7 +165,9 @@ void CTFCoder::decompress(const CompressedDigits& cd, VDIG& digitVec, VCHAN& cha uint32_t firstEntry = 0, clCount = 0, chipCount = 0; o2::InteractionRecord ir(cd.header.firstBC, cd.header.firstOrbit); - + if (mBCShift && ir.toLong() >= mBCShift) { + ir -= mBCShift; + } for (uint32_t idig = 0; idig < cd.header.nTriggers; idig++) { // restore ROFRecord if (cd.orbitInc[idig]) { // non-0 increment => new orbit diff --git a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/ReadRaw.h b/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/ReadRaw.h deleted file mode 100644 index 54c8b7b203edb..0000000000000 --- a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/ReadRaw.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ReadRaw.h -/// \brief Reads raw data and converts to digits -/// \author Maciej.Slupecki@cern.ch, arvind.khuntia@cern.ch, based on the FT0 code -// RAW data format description: DataFormat/Detectors/FIT/FDD/RawEventData - -#ifndef ALICEO2_FDD_READRAW_H_ -#define ALICEO2_FDD_READRAW_H_ - -#include -#include -#include -#include -#include -#include -#include -#include "TBranch.h" -#include "TTree.h" -#include "CommonDataFormat/InteractionRecord.h" -#include "DataFormatsFDD/Digit.h" -#include "DataFormatsFDD/ChannelData.h" -#include "DataFormatsFDD/LookUpTable.h" -#include "DataFormatsFDD/RawEventData.h" - -namespace o2 -{ -namespace fdd -{ -class ReadRaw -{ - public: - ReadRaw() = default; - ReadRaw(bool doConversionToDigits, const std::string inputRawFilePath = "fdd.raw", const std::string outputRawFilePath = "fdddigitsFromRaw.root"); - void readRawData(const LookUpTable& lut); - void writeDigits(const std::string& outputDigitsFilePath); - void close(); - - private: - std::ifstream mRawFileIn; - std::map> mDigitAccum; // digit accumulator - - template - TBranch* getOrMakeBranch(TTree& tree, std::string brname, T* ptr) - { - if (auto br = tree.GetBranch(brname.c_str())) { - br->SetAddress(static_cast(ptr)); - return br; - } - // otherwise make it - return tree.Branch(brname.c_str(), ptr); - } - - ClassDefNV(ReadRaw, 1); -}; - -} // namespace fdd -} // namespace o2 -#endif diff --git a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/Reconstructor.h b/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/Reconstructor.h index 161b800a2c3ca..8881605b652ac 100644 --- a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/Reconstructor.h +++ b/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/Reconstructor.h @@ -17,6 +17,7 @@ #include #include "DataFormatsFDD/Digit.h" #include "DataFormatsFDD/RecPoint.h" +#include "DataFormatsFIT/DeadChannelMap.h" namespace o2 { namespace fdd @@ -30,10 +31,16 @@ class Reconstructor gsl::span inChData, std::vector& RecPoints, std::vector& outChData); - void finish(); + void setDeadChannelMap(o2::fit::DeadChannelMap const* deadChannelMap) + { + LOG(info) << "Updated dead channel map"; + mDeadChannelMap = deadChannelMap; + } + private: + o2::fit::DeadChannelMap const* mDeadChannelMap = nullptr; ClassDefNV(Reconstructor, 3); }; } // namespace fdd diff --git a/Detectors/FIT/FDD/reconstruction/src/Reconstructor.cxx b/Detectors/FIT/FDD/reconstruction/src/Reconstructor.cxx index 3a87a11046a77..7d133e30df08e 100644 --- a/Detectors/FIT/FDD/reconstruction/src/Reconstructor.cxx +++ b/Detectors/FIT/FDD/reconstruction/src/Reconstructor.cxx @@ -33,7 +33,12 @@ void Reconstructor::process(o2::fdd::Digit const& digitBC, gsl::spanisChannelAlive(inChData[ich].mPMNumber)) { + LOG(debug) << "Channel " << ich << " is dead - discarding data"; + continue; + } bool inTime = inChData[ich].getFlag(ChannelData::EEventDataBit::kIsEventInTVDC); bool inAdcGate = inChData[ich].getFlag(ChannelData::EEventDataBit::kIsCFDinADCgate); if (inAdcGate) { diff --git a/Detectors/FIT/FDD/simulation/include/FDDSimulation/Digits2Raw.h b/Detectors/FIT/FDD/simulation/include/FDDSimulation/Digits2Raw.h deleted file mode 100644 index 4afcf5da37ae8..0000000000000 --- a/Detectors/FIT/FDD/simulation/include/FDDSimulation/Digits2Raw.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file Digits2Raw.h -/// \brief converts digits to raw format -/// \author Maciej.Slupecki@cern.ch -// based on FV0 - -#ifndef ALICEO2_FDD_DIGITS2RAW_H_ -#define ALICEO2_FDD_DIGITS2RAW_H_ - -#include "Headers/RAWDataHeader.h" -#include "CommonDataFormat/InteractionRecord.h" -#include "DataFormatsFDD/RawEventData.h" -#include "DataFormatsFDD/LookUpTable.h" -#include "DataFormatsFDD/ChannelData.h" -#include "DataFormatsFDD/Digit.h" -#include "DetectorsRaw/HBFUtils.h" -#include "DetectorsRaw/RawFileWriter.h" -#include -#include -#include -#include -#include -#include - -namespace o2 -{ -namespace fdd -{ -class Digits2Raw -{ - public: - Digits2Raw() = default; - void readDigits(const std::string& outDir, const std::string& fileDigitsName); - void convertDigits(o2::fdd::Digit bcdigits, - gsl::span pmchannels, - const o2::fdd::LookUpTable& lut); - - o2::raw::RawFileWriter& getWriter() { return mWriter; } - void setFilePerLink(bool v) { mOutputPerLink = v; } - bool getFilePerLink() const { return mOutputPerLink; } - - int carryOverMethod(const header::RDHAny* rdh, const gsl::span data, - const char* ptr, int maxSize, int splitID, - std::vector& trailer, std::vector& header) const; - - private: - static constexpr uint32_t sTcmLink = 2; - static constexpr uint16_t sCruId = 0; - static constexpr uint32_t sEndPointId = sCruId; - - 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; - ///////////////////////////////////////////////// - - ClassDefNV(Digits2Raw, 1); -}; - -} // namespace fdd -} // namespace o2 -#endif diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyDecoderSpec.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyDecoderSpec.h index a6ee132ee0c34..1fd3cd7835cd9 100644 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyDecoderSpec.h +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyDecoderSpec.h @@ -28,7 +28,7 @@ namespace fdd class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity); + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -41,7 +41,7 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt); } // namespace fdd } // namespace o2 diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyEncoderSpec.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyEncoderSpec.h index 87dcca02e869f..37d43f477e836 100644 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyEncoderSpec.h +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyEncoderSpec.h @@ -28,7 +28,7 @@ namespace fdd class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR); + EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -42,7 +42,7 @@ class EntropyEncoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); } // namespace fdd } // namespace o2 diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataProcessSpec.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataProcessSpec.h deleted file mode 100644 index 6ed465b6181dd..0000000000000 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataProcessSpec.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @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 -#include -#include - -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 deleted file mode 100644 index c3b0349826e98..0000000000000 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataReaderSpec.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file 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 "DetectorsRaw/RDHUtils.h" - -#include -#include -#include -using namespace o2::framework; - -namespace o2 -{ -namespace fdd -{ -template -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 = reinterpret_cast(it.raw()); - gsl::span payload(it.data(), it.size()); - mRawReader.process(payload, o2::raw::RDHUtils::getLinkID(rdhPtr), int(0)); - } - LOG(info) << "Pages: " << count; - mRawReader.accumulateDigits(); - mRawReader.makeSnapshot(pc); - } - RawReader mRawReader; -}; - -template -framework::DataProcessorSpec getFDDRawDataReaderSpec(const RawReader& rawReader) -{ - LOG(info) << "DataProcessorSpec initDataProcSpec() for RawReaderFDD"; - std::vector outputSpec; - RawReader::prepareOutputSpec(outputSpec); - return DataProcessorSpec{ - "fdd-datareader-dpl", - o2::framework::select("TF:FDD/RAWDATA"), - outputSpec, - adaptFromTask>(rawReader), - Options{}}; -} - -} // namespace fdd -} // namespace o2 - -#endif /* O2_FDDDATAREADERDPL_H */ diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecoWorkflow.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecoWorkflow.h index 2dbd854e34eee..0d5d308216bb0 100644 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecoWorkflow.h +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecoWorkflow.h @@ -20,7 +20,7 @@ namespace o2 { namespace fdd { -framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut); +framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut, bool useDeadChannelMap); } // 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 7dcb5d9aaba40..8f20ff1513ab4 100644 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/ReconstructorSpec.h +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/ReconstructorSpec.h @@ -18,6 +18,8 @@ #include "Framework/Task.h" #include "FDDReconstruction/Reconstructor.h" #include "DataFormatsFDD/RecPoint.h" +#include "DataFormatsFIT/DeadChannelMap.h" +#include "Framework/ConcreteDataMatcher.h" using namespace o2::framework; @@ -29,21 +31,25 @@ namespace fdd class FDDReconstructorDPL : public Task { public: - FDDReconstructorDPL(bool useMC) : mUseMC(useMC) {} + FDDReconstructorDPL(bool useMC, bool useDeadChannelMap) : mUseMC(useMC), mUseDeadChannelMap(useDeadChannelMap) {} ~FDDReconstructorDPL() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; + void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final; private: bool mUseMC = true; + bool mUseDeadChannelMap = true; + bool mUpdateDeadChannelMap = true; std::vector mRecPoints; std::vector mRecChData; + o2::fit::DeadChannelMap const* mDeadChannelMap; o2::fdd::Reconstructor mReco; o2::header::DataOrigin mOrigin = o2::header::gDataOriginFDD; }; /// create a processor spec -framework::DataProcessorSpec getFDDReconstructorSpec(bool useMC = true); +framework::DataProcessorSpec getFDDReconstructorSpec(bool useMC = true, bool useDeadChannelMap = true); } // namespace fdd } // namespace o2 diff --git a/Detectors/FIT/FDD/workflow/src/EntropyDecoderSpec.cxx b/Detectors/FIT/FDD/workflow/src/EntropyDecoderSpec.cxx index fb5b173fb7a94..43615b175734d 100644 --- a/Detectors/FIT/FDD/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/FIT/FDD/workflow/src/EntropyDecoderSpec.cxx @@ -24,12 +24,12 @@ namespace o2 { namespace fdd { - -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); mCTFCoder.setVerbosity(verbosity); + mCTFCoder.setSupportBCShifts(true); mCTFCoder.setDictBinding("ctfdict_FDD"); } @@ -73,7 +73,7 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"digits"}, "FDD", "DIGITSBC", 0, Lifetime::Timeframe}, @@ -82,17 +82,18 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) std::vector inputs; inputs.emplace_back("ctf_FDD", "FDD", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_FDD", "FDD", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FDD/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_FDD", "FDD", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FDD/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ "fdd-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace fdd } // namespace o2 diff --git a/Detectors/FIT/FDD/workflow/src/EntropyEncoderSpec.cxx b/Detectors/FIT/FDD/workflow/src/EntropyEncoderSpec.cxx index abb2518e5ae0b..be81f7ca7d3d4 100644 --- a/Detectors/FIT/FDD/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/FIT/FDD/workflow/src/EntropyEncoderSpec.cxx @@ -25,8 +25,7 @@ namespace o2 { namespace fdd { - -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR) { mTimer.Stop(); mTimer.Reset(); @@ -69,12 +68,15 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("digits", "FDD", "DIGITSBC", 0, Lifetime::Timeframe); inputs.emplace_back("channels", "FDD", "DIGITSCH", 0, Lifetime::Timeframe); - inputs.emplace_back("ctfdict", "FDD", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FDD/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "FDD", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FDD/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -82,13 +84,11 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR) "fdd-entropy-encoder", inputs, Outputs{{"FDD", "CTFDATA", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace fdd } // namespace o2 diff --git a/Detectors/FIT/FDD/workflow/src/RawDataProcessSpec.cxx b/Detectors/FIT/FDD/workflow/src/RawDataProcessSpec.cxx deleted file mode 100644 index bf18db67672c2..0000000000000 --- a/Detectors/FIT/FDD/workflow/src/RawDataProcessSpec.cxx +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @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>("digits"); - auto vecChannelData = pc.inputs().get>("digch"); - if (mDumpEventBlocks) { - DigitBlockFDD::print(vecDigits, vecChannelData); - } -} - -DataProcessorSpec getFDDRawDataProcessSpec(bool dumpProcessor) -{ - std::vector 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(dumpProcessor)}, - Options{}}; -} - -} // namespace fdd -} // namespace o2 diff --git a/Detectors/FIT/FDD/workflow/src/RawWorkflow.cxx b/Detectors/FIT/FDD/workflow/src/RawWorkflow.cxx deleted file mode 100644 index c9e5c5be0c81d..0000000000000 --- a/Detectors/FIT/FDD/workflow/src/RawWorkflow.cxx +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file 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/RecoWorkflow.cxx b/Detectors/FIT/FDD/workflow/src/RecoWorkflow.cxx index a7d4c15af81bb..b464e689f7a75 100644 --- a/Detectors/FIT/FDD/workflow/src/RecoWorkflow.cxx +++ b/Detectors/FIT/FDD/workflow/src/RecoWorkflow.cxx @@ -22,14 +22,14 @@ namespace o2 namespace fdd { -framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut) +framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut, bool useDeadChannelMap) { framework::WorkflowSpec specs; if (!disableRootInp) { specs.emplace_back(o2::fdd::getFDDDigitReaderSpec(useMC)); } - specs.emplace_back(o2::fdd::getFDDReconstructorSpec(useMC)); + specs.emplace_back(o2::fdd::getFDDReconstructorSpec(useMC, useDeadChannelMap)); if (!disableRootOut) { specs.emplace_back(o2::fdd::getFDDRecPointWriterSpec(useMC)); } diff --git a/Detectors/FIT/FDD/workflow/src/ReconstructorSpec.cxx b/Detectors/FIT/FDD/workflow/src/ReconstructorSpec.cxx index b7a0b9876a2ee..1d5d599b5ee31 100644 --- a/Detectors/FIT/FDD/workflow/src/ReconstructorSpec.cxx +++ b/Detectors/FIT/FDD/workflow/src/ReconstructorSpec.cxx @@ -18,6 +18,7 @@ #include "FDDWorkflow/ReconstructorSpec.h" #include "DataFormatsFDD/Digit.h" #include "DataFormatsFDD/MCLabel.h" +#include "Framework/CCDBParamSpec.h" using namespace o2::framework; @@ -44,6 +45,11 @@ void FDDReconstructorDPL::run(ProcessingContext& pc) // lblPtr = labels.get(); LOG(info) << "Ignoring MC info"; } + if (mUseDeadChannelMap && mUpdateDeadChannelMap) { + LOG(info) << "Populating reconsturctor object with Dead Channel Map object"; + auto deadChannelMap = pc.inputs().get("deadChannelMap"); + mReco.setDeadChannelMap(deadChannelMap.get()); + } int nDig = digitsBC.size(); mRecPoints.reserve(nDig); mRecChData.reserve(digitsCh.size()); @@ -58,16 +64,29 @@ void FDDReconstructorDPL::run(ProcessingContext& pc) pc.outputs().snapshot(Output{mOrigin, "RECCHDATA", 0}, mRecChData); } -DataProcessorSpec getFDDReconstructorSpec(bool useMC) +void FDDReconstructorDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) +{ + if (matcher == ConcreteDataMatcher("FDD", "DeadChannelMap", 0)) { + mUpdateDeadChannelMap = false; + return; + } +} + +DataProcessorSpec getFDDReconstructorSpec(bool useMC, bool useDeadChannelMap) { std::vector inputSpec; std::vector outputSpec; inputSpec.emplace_back("digitsBC", o2::header::gDataOriginFDD, "DIGITSBC", 0, Lifetime::Timeframe); inputSpec.emplace_back("digitsCh", o2::header::gDataOriginFDD, "DIGITSCH", 0, Lifetime::Timeframe); + if (useMC) { LOG(info) << "Currently FDDReconstructor does not consume and provide MC truth"; // inputSpec.emplace_back("labels", o2::header::gDataOriginFDD, "DIGITSMCTR", 0, Lifetime::Timeframe); } + if (useDeadChannelMap) { + LOG(info) << "Dead channel map will be applied during reconstruction"; + inputSpec.emplace_back("deadChannelMap", o2::header::gDataOriginFDD, "DeadChannelMap", 0, Lifetime::Condition, ccdbParamSpec("FDD/Calib/DeadChannelMap")); + } outputSpec.emplace_back(o2::header::gDataOriginFDD, "RECPOINTS", 0, Lifetime::Timeframe); outputSpec.emplace_back(o2::header::gDataOriginFDD, "RECCHDATA", 0, Lifetime::Timeframe); @@ -75,7 +94,7 @@ DataProcessorSpec getFDDReconstructorSpec(bool useMC) "fdd-reconstructor", inputSpec, outputSpec, - AlgorithmSpec{adaptFromTask(useMC)}, + AlgorithmSpec{adaptFromTask(useMC, useDeadChannelMap)}, Options{}}; } diff --git a/Detectors/FIT/FDD/workflow/src/entropy-encoder-workflow.cxx b/Detectors/FIT/FDD/workflow/src/entropy-encoder-workflow.cxx index bcc42ebc2e086..b83e25557e760 100644 --- a/Detectors/FIT/FDD/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/FIT/FDD/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "none", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -37,6 +38,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::fdd::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"))); + wf.emplace_back(o2::fdd::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/FIT/FDD/workflow/src/fdd-reco-workflow.cxx b/Detectors/FIT/FDD/workflow/src/fdd-reco-workflow.cxx index 652ddb8bd2a29..888792425909b 100644 --- a/Detectors/FIT/FDD/workflow/src/fdd-reco-workflow.cxx +++ b/Detectors/FIT/FDD/workflow/src/fdd-reco-workflow.cxx @@ -38,6 +38,7 @@ void customize(std::vector& 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 readers"}}, {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}, + {"disable-dead-channel-map", o2::framework::VariantType::Bool, false, {"disable dead channel map"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); @@ -57,8 +58,9 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto useMC = !configcontext.options().get("disable-mc"); auto disableRootInp = configcontext.options().get("disable-root-input"); auto disableRootOut = configcontext.options().get("disable-root-output"); + bool useDeadChannelMap = !configcontext.options().get("disable-dead-channel-map"); - auto wf = o2::fdd::getRecoWorkflow(useMC, disableRootInp, disableRootOut); + auto wf = o2::fdd::getRecoWorkflow(useMC, disableRootInp, disableRootOut, useDeadChannelMap); // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit o2::raw::HBFUtilsInitializer hbfIni(configcontext, wf); diff --git a/Detectors/FIT/FT0/base/include/FT0Base/FT0DigParam.h b/Detectors/FIT/FT0/base/include/FT0Base/FT0DigParam.h index 2bf774859aa22..074d91bb04b27 100644 --- a/Detectors/FIT/FT0/base/include/FT0Base/FT0DigParam.h +++ b/Detectors/FIT/FT0/base/include/FT0Base/FT0DigParam.h @@ -31,8 +31,8 @@ struct FT0DigParam : o2::conf::ConfigurableParamHelper { float mAmpRecordUp = 15; // to [ns] float hitTimeOffsetA = 0; ///< hit time offset on the A side [ns] float hitTimeOffsetC = 0; ///< hit time offset on the C side [ns] - int mtrg_central_trh = 600.; // channels - int mtrg_semicentral_trh = 300.; // channels + int mtrg_central_trh = 40; // Tclu units (40 for pp and 1433 for PbPb in Run3) + int mtrg_semicentral_trh = 20; // Tclu units (20 for pp and 35 for PbPb in Run3) float mMip_in_V = 7; // MIP to mV float mPe_in_mip = 0.004; // invserse Np.e. in MIP 1./250. @@ -43,11 +43,12 @@ struct FT0DigParam : o2::conf::ConfigurableParamHelper { float mNoiseVar = 0.1; // noise level float mNoisePeriod = 1 / 0.9; // GHz low frequency noise period; short mTime_trg_gate = 153; // #channels as in TCM as in Pilot beams ('OR gate' setting in TCM tab in ControlServer) + short mTime_trg_vertex_gate = 100; // #channels as in TCM as in Pilot beams ('OR gate' setting in TCM tab in ControlServer) float mAmpThresholdForReco = 5; // only channels with amplitude higher will participate in calibration and collision time: 0.3 MIP short mTimeThresholdForReco = 1000; // only channels with time below will participate in calibration and collision time - float mMV_2_Nchannels = 2.2857143; // amplitude channel 7 mV ->16channels - float mMV_2_NchannelsInverse = 0.437499997; // inverse amplitude channel 7 mV ->16channels + float mMV_2_Nchannels = 2.; // amplitude channel 7 mV ->14channels + float mMV_2_NchannelsInverse = 0.5; // inverse amplitude channel 7 mV ->14channels (nowhere used) O2ParamDef(FT0DigParam, "FT0DigParam"); }; diff --git a/Detectors/FIT/FT0/calibration/CMakeLists.txt b/Detectors/FIT/FT0/calibration/CMakeLists.txt index d103b4a9a18b6..bee0493d300c1 100644 --- a/Detectors/FIT/FT0/calibration/CMakeLists.txt +++ b/Detectors/FIT/FT0/calibration/CMakeLists.txt @@ -10,26 +10,50 @@ # or submit itself to any jurisdiction. o2_add_library(FT0Calibration - SOURCES - src/FT0TimeOffsetSlotContainer.cxx - PUBLIC_LINK_LIBRARIES - O2::DataFormatsFT0 - O2::CommonDataFormat - O2::DetectorsCalibration - ) - o2_target_root_dictionary(FT0Calibration - HEADERS - include/FT0Calibration/FT0TimeOffsetSlotContainer.h - ) - o2_add_executable(ft0-time-offset-calib - COMPONENT_NAME calibration - SOURCES workflow/FT0TimeOffsetCalibration-Workflow.cxx - PUBLIC_LINK_LIBRARIES - O2::FT0Calibration O2::FITCalibration - ) - o2_add_executable(ft0-time-spectra-processor - COMPONENT_NAME calibration - SOURCES workflow/FT0TimeSpectraProcessor-Workflow.cxx - PUBLIC_LINK_LIBRARIES - O2::FT0Calibration - ) + SOURCES + src/FT0TimeOffsetSlotContainer.cxx + src/EventsPerBcCalibrator.cxx + PUBLIC_LINK_LIBRARIES + O2::DetectorsCalibration + O2::Framework + O2::CommonUtils + Microsoft.GSL::GSL + O2::DataFormatsFT0 + O2::CommonDataFormat + O2::Steer + O2::CCDB + ROOT::Minuit + ROOT::Hist + ) + +o2_target_root_dictionary(FT0Calibration + HEADERS + include/FT0Calibration/FT0TimeOffsetSlotContainer.h + include/FT0Calibration/EventsPerBcCalibrator.h + ) + +o2_add_executable(ft0-time-offset-calib + COMPONENT_NAME calibration + SOURCES + workflow/FT0TimeOffsetCalibration-Workflow.cxx + PUBLIC_LINK_LIBRARIES + O2::FT0Calibration O2::FITCalibration + ) + +o2_add_executable(ft0-time-spectra-processor + COMPONENT_NAME calibration + SOURCES + workflow/FT0TimeSpectraProcessor-Workflow.cxx + PUBLIC_LINK_LIBRARIES + O2::FT0Calibration + ) + +o2_add_executable(ft0-events-per-bc-processor + COMPONENT_NAME calibration + SOURCES + workflow/FT0EventsPerBcProcessor-Workflow.cxx + PUBLIC_LINK_LIBRARIES + O2::FT0Calibration + O2::Framework + O2::CCDB +) \ No newline at end of file diff --git a/Detectors/FIT/FT0/calibration/README.md b/Detectors/FIT/FT0/calibration/README.md new file mode 100644 index 0000000000000..78b0f980400d2 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/README.md @@ -0,0 +1,62 @@ +# Calibrations + +## Events per BC Calibration +### Description +Generates histograms of **Events per Bunch Crossing (BC)**. Events can be filtered by applying amplitude thresholds to the **A-side** and **C-side**. + +### Command-Line Options +| Option | Default | Description | +| :--- | :--- | :--- | +| `--slot-len-sec` | `3600` | Duration of each slot in seconds. | +| `--slot-len-tf` | `0` | Slot length in Time Frames (TFs). | +| `--one-object-per-run` | — | If set, the workflow creates only one calibration object per run. | +| `--min-entries-number` | `0` | Minimum number of entries required for a slot to be valid. | +| `--min-ampl-side-a` | `-2147483648` | Amplitude threshold for Side A events. | +| `--min-ampl-side-c` | `-2147483648` | Amplitude threshold for Side C events. | + +--- + +## How to Run + +### Simulation Data +First, it is important to digitize data with a non-zero run number, orbit, and timestamp. To set these parameters, one can use the `--configKeyValues` option, as shown in the example below. +``` +o2-sim-digitizer-workflow \ +--onlyDet FT0 \ +--configKeyValues="HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=128;HBFUtils.orbitFirstSampled=256;HBFUtils.runNumber=560560;HBFUtils.startTime=1768464099000" +``` + +To process simulation data, digits must first be converted to RAW format. The `o2-ft0-digi2raw` tool performs this conversion and generates the required configuration file. + +Once converted, you can run the calibration either as a single integrated workflow or by spawning as the sender and receiver components separately. + +#### Single Workflow Example +Execute the following command within the simulation directory: +``` +o2-raw-file-reader-workflow --input-conf FT0raw.cfg --loop -1 \ +| o2-ft0-flp-dpl-workflow --condition-backend=http://localhost:8080 \ +| o2-calibration-ft0-events-per-bc-processor --FT0EventsPerBcProcessor "--slot-len-sec=10" \ +| o2-calibration-ccdb-populator-workflow --ccdb-path=http://localhost:8080 +``` + +Sender example (in simulation directory): +``` +o2-raw-file-reader-workflow --input-conf FT0raw.cfg --loop -1 \ +| o2-ft0-flp-dpl-workflow --condition-backend=http://localhost:8080 \ +| o2-dpl-output-proxy --channel-config "name=downstream,method=connect,address=tcp://localhost:30453,type=push,transport=zeromq" --dataspec "downstream:FT0/DIGITSBC" +``` + +Receiver example: +``` +o2-dpl-raw-proxy --channel-config "name=readout-proxy,type=pull,method=bind,address=tcp://localhost:30453,rateLogging=1,transport=zeromq" --dataspec "A:FT0/DIGITSBC/0" \ +| o2-calibration-ft0-events-per-bc-processor --FT0EventsPerBcProcessor "--slot-len-sec=10 --min-ampl-side-a=0" \ +| o2-calibration-ccdb-populator-workflow --ccdb-path=http://localhost:8080/ +``` + +### CTF Data +Example: +``` +o2-ctf-reader-workflow --ctf-input ctf.root --onlyDet FT0 \ +| o2-calibration-ft0-events-per-bc-processor --FT0EventsPerBcProcessor "--slot-len-sec=10" \ +| o2-calibration-ccdb-populator-workflow --ccdb-path=http://localhost:8080/ +``` \ No newline at end of file diff --git a/Detectors/FIT/FT0/calibration/include/FT0Calibration/EventsPerBcCalibrator.h b/Detectors/FIT/FT0/calibration/include/FT0Calibration/EventsPerBcCalibrator.h new file mode 100644 index 0000000000000..d831cc36201ab --- /dev/null +++ b/Detectors/FIT/FT0/calibration/include/FT0Calibration/EventsPerBcCalibrator.h @@ -0,0 +1,83 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FT0TVXPERBCID +#define O2_FT0TVXPERBCID + +#include +#include +#include +#include + +#include "CommonDataFormat/FlatHisto2D.h" +#include "CommonConstants/LHCConstants.h" +#include "DataFormatsFT0/SpectraInfoObject.h" +#include "DataFormatsFT0/Digit.h" +#include "DataFormatsFT0/EventsPerBc.h" +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DetectorsCalibration/TimeSlot.h" +#include "CommonDataFormat/TFIDInfo.h" +#include "TH1F.h" +#include "Rtypes.h" + +namespace o2::ft0 +{ +struct EventsPerBcContainer { + EventsPerBcContainer(int32_t minAmplitudeSideA, int32_t minAmplitudeSideC, int32_t minSumOfAmplitude) : mMinAmplitudeSideA(minAmplitudeSideA), mMinAmplitudeSideC(minAmplitudeSideC), mMinSumOfAmplitude(minSumOfAmplitude) {} + + size_t getEntries() const { return entries; } + void print() const; + void fill(const o2::dataformats::TFIDInfo& ti, const gsl::span data); + void merge(const EventsPerBcContainer* prev); + + const int32_t mMinAmplitudeSideA; + const int32_t mMinAmplitudeSideC; + const int32_t mMinSumOfAmplitude; + + std::array mTvx{0.0}; + size_t entries{0}; + long startTimeStamp{0}; + long stopTimeStamp{0}; + + ClassDefNV(EventsPerBcContainer, 1); +}; + +class EventsPerBcCalibrator final : public o2::calibration::TimeSlotCalibration +{ + using Slot = o2::calibration::TimeSlot; + using TFType = o2::calibration::TFType; + using EventsHistogram = std::array; + + public: + EventsPerBcCalibrator(uint32_t minNumberOfEntries, int32_t minAmplitudeSideA, int32_t minAmplitudeSideC, int32_t minSumOfAmplitude); + + bool hasEnoughData(const Slot& slot) const override; + void initOutput() override; + void finalizeSlot(Slot& slot) override; + Slot& emplaceNewSlot(bool front, TFType tstart, TFType tend) override; + + const std::vector& getTvxPerBc() { return mTvxPerBcs; } + std::vector>& getTvxPerBcCcdbInfo() { return mTvxPerBcInfos; } + + private: + const uint32_t mMinNumberOfEntries; + const int32_t mMinAmplitudeSideA; + const int32_t mMinAmplitudeSideC; + const int32_t mMinSumOfAmplitude; + + std::vector mTvxPerBcs; + std::vector> mTvxPerBcInfos; + + ClassDefOverride(EventsPerBcCalibrator, 1); +}; +} // namespace o2::ft0 + +#endif diff --git a/Detectors/FIT/FT0/calibration/src/EventsPerBcCalibrator.cxx b/Detectors/FIT/FT0/calibration/src/EventsPerBcCalibrator.cxx new file mode 100644 index 0000000000000..b17c81213cd08 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/src/EventsPerBcCalibrator.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 "FT0Calibration/EventsPerBcCalibrator.h" +#include "CommonUtils/MemFileHelper.h" + +namespace o2::ft0 +{ +void EventsPerBcContainer::print() const +{ + LOG(info) << entries << " entries"; +} + +void EventsPerBcContainer::fill(const o2::dataformats::TFIDInfo& ti, const gsl::span data) +{ + size_t oldEntries = entries; + for (const auto& digit : data) { + if (digit.mTriggers.getVertex() && digit.mTriggers.getAmplA() >= mMinAmplitudeSideA && digit.mTriggers.getAmplC() >= mMinAmplitudeSideC && (digit.mTriggers.getAmplA() + digit.mTriggers.getAmplC()) >= mMinSumOfAmplitude) { + mTvx[digit.mIntRecord.bc]++; + entries++; + } + } + LOG(debug) << "Container is filled with " << entries - oldEntries << " new events"; +} + +void EventsPerBcContainer::merge(const EventsPerBcContainer* prev) +{ + for (int bc = 0; bc < o2::constants::lhc::LHCMaxBunches; bc++) { + mTvx[bc] += prev->mTvx[bc]; + } + entries += prev->entries; +} + +void EventsPerBcCalibrator::initOutput() +{ + mTvxPerBcs.clear(); + mTvxPerBcInfos.clear(); +} + +EventsPerBcCalibrator::EventsPerBcCalibrator(uint32_t minNumberOfEntries, int32_t minAmplitudeSideA, int32_t minAmplitudeSideC, int32_t minSumOfAmplitude) : mMinNumberOfEntries(minNumberOfEntries), mMinAmplitudeSideA(minAmplitudeSideA), mMinAmplitudeSideC(minAmplitudeSideC), mMinSumOfAmplitude(minSumOfAmplitude) +{ + LOG(info) << "Defined threshold for number of entires per slot: " << mMinNumberOfEntries; + LOG(info) << "Defined threshold for side A amplitude for event: " << mMinAmplitudeSideA; + LOG(info) << "Defined threshold for side C amplitude for event: " << mMinAmplitudeSideC; +} + +bool EventsPerBcCalibrator::hasEnoughData(const EventsPerBcCalibrator::Slot& slot) const +{ + return slot.getContainer()->entries > mMinNumberOfEntries; +} + +void EventsPerBcCalibrator::finalizeSlot(EventsPerBcCalibrator::Slot& slot) +{ + LOG(info) << "Finalizing slot from " << slot.getStartTimeMS() << " to " << slot.getEndTimeMS(); + o2::ft0::EventsPerBcContainer* data = slot.getContainer(); + mTvxPerBcs.emplace_back(data->mTvx); + + auto clName = o2::utils::MemFileHelper::getClassName(mTvxPerBcs.back()); + auto flName = o2::ccdb::CcdbApi::generateFileName(clName); + + std::map metaData; + mTvxPerBcInfos.emplace_back(std::make_unique("FT0/Calib/EventsPerBc", clName, flName, metaData, slot.getStartTimeMS(), slot.getEndTimeMS())); + LOG(info) << "Created object valid from " << mTvxPerBcInfos.back()->getStartValidityTimestamp() << " to " << mTvxPerBcInfos.back()->getEndValidityTimestamp(); +} + +EventsPerBcCalibrator::Slot& EventsPerBcCalibrator::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(mMinAmplitudeSideA, mMinAmplitudeSideC, mMinSumOfAmplitude)); + return slot; +} +} // namespace o2::ft0 \ No newline at end of file diff --git a/Detectors/FIT/FT0/calibration/src/FT0CalibrationLinkDef.h b/Detectors/FIT/FT0/calibration/src/FT0CalibrationLinkDef.h index 49f72e8cbdfff..11b1ce25e9353 100644 --- a/Detectors/FIT/FT0/calibration/src/FT0CalibrationLinkDef.h +++ b/Detectors/FIT/FT0/calibration/src/FT0CalibrationLinkDef.h @@ -16,7 +16,9 @@ #pragma link off all functions; #pragma link C++ class o2::ft0::FT0TimeOffsetSlotContainer + ; +#pragma link C++ class o2::ft0::EventsPerBcCalibrator + ; #pragma link C++ class o2::calibration::TimeSlot < o2::ft0::FT0TimeOffsetSlotContainer>; #pragma link C++ class o2::calibration::TimeSlotCalibration < o2::ft0::FT0TimeOffsetSlotContainer>; - +#pragma link C++ class o2::calibration::TimeSlot < o2::ft0::EventsPerBcContainer> + ; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::ft0::EventsPerBcContainer> + ; #endif diff --git a/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcProcessor-Workflow.cxx b/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcProcessor-Workflow.cxx new file mode 100644 index 0000000000000..38d634c20c828 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcProcessor-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 "FT0EventsPerBcSpec.h" +#include "Framework/Lifetime.h" +#include + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) +{ + using namespace o2::framework; + using o2::calibration::FT0EventsPerBcProcessor; + std::vector inputs; + inputs.emplace_back("digits", "FT0", "DIGITSBC", Lifetime::Timeframe); + auto ccdbRequest = std::make_shared(true, // orbitResetTime + false, // GRPECS=true + false, // GRPLHCIF + false, // GRPMagField + false, // askMatLUT + o2::base::GRPGeomRequest::None, // geometry + inputs); + std::vector outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "EventsPerBc"}, Lifetime::Timeframe); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "EventsPerBc"}, Lifetime::Timeframe); + DataProcessorSpec dataProcessorSpec{ + "FT0EventsPerBcProcessor", + inputs, + outputs, + AlgorithmSpec(adaptFromTask(ccdbRequest)), + Options{ + {"save-to-file", VariantType::Bool, false, {"Save calibration object to local file"}}, + {"slot-len-sec", VariantType::UInt32, 3600u, {"Duration of each slot in seconds"}}, + {"one-object-per-run", VariantType::Bool, false, {"If set, workflow creates only one calibration object per run"}}, + {"min-entries-number", VariantType::UInt32, 5000u, {"Minimum number of entries required for a slot to be valid"}}, + {"min-ampl-side-a", VariantType::Int, 0, {"Amplitude threshold for Side A events"}}, + {"min-ampl-side-c", VariantType::Int, 0, {"Amplitude threshold for Side C events"}}, + {"min-sum-of-ampl", VariantType::Int, 0, {"Amplitude threshold for sum of A-side and C-side amplitudes"}}}}; + + WorkflowSpec workflow; + workflow.emplace_back(dataProcessorSpec); + return workflow; +} diff --git a/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcSpec.h b/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcSpec.h new file mode 100644 index 0000000000000..1d4d4a75842e8 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcSpec.h @@ -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. + +#ifndef O2_CALIBRATION_FT0_EVENTS_PER_BC_CALIBRATOR_H +#define O2_CALIBRATION_FT0_EVENTS_PER_BC_CALIBRATOR_H + +#include "Framework/runDataProcessing.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" +#include +#include "Framework/DeviceSpec.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Task.h" +#include "DetectorsCalibration/Utils.h" +#include "DetectorsBase/GRPGeomHelper.h" + +#include "DataFormatsFT0/Digit.h" +#include "FT0Calibration/EventsPerBcCalibrator.h" + +namespace o2::calibration +{ +class FT0EventsPerBcProcessor final : public o2::framework::Task +{ + public: + FT0EventsPerBcProcessor(std::shared_ptr request) : mCCDBRequest(request) {} + + void init(o2::framework::InitContext& ic) final + { + o2::base::GRPGeomHelper::instance().setRequest(mCCDBRequest); + mSaveToFile = ic.options().get("save-to-file"); + + if (ic.options().hasOption("slot-len-sec")) { + mSlotLenSec = ic.options().get("slot-len-sec"); + } + if (ic.options().hasOption("one-object-per-run")) { + mOneObjectPerRun = ic.options().get("one-object-per-run"); + } + if (ic.options().hasOption("min-entries-number")) { + mMinNumberOfEntries = ic.options().get("min-entries-number"); + } + if (ic.options().hasOption("min-ampl-side-a")) { + mMinAmplitudeSideA = ic.options().get("min-ampl-side-a"); + } + if (ic.options().hasOption("min-ampl-side-c")) { + mMinAmplitudeSideC = ic.options().get("min-ampl-side-c"); + } + if (ic.options().hasOption("min-sum-of-ampl")) { + mMinSumOfAmplitude = ic.options().get("min-sum-of-ampl"); + } + + mCalibrator = std::make_unique(mMinNumberOfEntries, mMinAmplitudeSideA, mMinAmplitudeSideC, mMinSumOfAmplitude); + + if (mOneObjectPerRun) { + LOG(info) << "Only one object will be created at the end of run"; + mCalibrator->setUpdateAtTheEndOfRunOnly(); + } + if (mOneObjectPerRun == false) { + LOG(info) << "Defined slot interval to " << mSlotLenSec << " seconds"; + mCalibrator->setSlotLengthInSeconds(mSlotLenSec); + } + } + + void finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) + { + o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj); + } + + void run(o2::framework::ProcessingContext& pc) final + { + const auto& tinfo = pc.services().get(); + if (tinfo.globalRunNumberChanged || mRunNoFromDH < 1) { // new run is starting + mRunNoFromDH = tinfo.runNumber; + } + o2::base::GRPGeomHelper::instance().checkUpdates(pc); + auto digits = pc.inputs().get>("digits"); + o2::base::TFIDInfoHelper::fillTFIDInfo(pc, mCalibrator->getCurrentTFInfo()); + if (digits.size() == 0) { + return; + } + mCalibrator->process(digits); + if (mOneObjectPerRun == false) { + sendOutput(pc.outputs()); + } + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + LOG(info) << "Received end-of-stream, checking for slot to finalize..."; + mCalibrator->checkSlotsToFinalize(); + sendOutput(ec.outputs()); + mCalibrator->initOutput(); + } + + void sendOutput(o2::framework::DataAllocator& output) + { + using o2::framework::Output; + const auto& tvxHists = mCalibrator->getTvxPerBc(); + auto& infos = mCalibrator->getTvxPerBcCcdbInfo(); + for (unsigned int idx = 0; idx < tvxHists.size(); idx++) { + auto& info = infos[idx]; + const auto& payload = tvxHists[idx]; + + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, info.get()); + 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, "EventsPerBc", idx}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "EventsPerBc", idx}, *info.get()); + if (mSaveToFile) { + std::string fnout = fmt::format("ft0eventsPerBC_run_{}_{}_{}.root", mRunNoFromDH, info->getStartValidityTimestamp(), info->getEndValidityTimestamp()); + try { + TFile flout(fnout.c_str(), "recreate"); + flout.WriteObjectAny(&payload, "o2::ft0::EventsPerBc", o2::ccdb::CcdbApi::CCDBOBJECT_ENTRY); + LOGP(info, R"(Saved to file, can upload as: o2-ccdb-upload -f {} --starttimestamp {} --endtimestamp {} -k "ccdb_object" --path {} -m "runNumber={};AdjustableEOV=true;")", + fnout, info->getStartValidityTimestamp(), info->getEndValidityTimestamp(), info->getPath(), mRunNoFromDH); + flout.Close(); + } catch (const std::exception& ex) { + LOGP(error, "failed to store object to file {}, error: {}", fnout, ex.what()); + } + } + } + + if (tvxHists.size()) { + mCalibrator->initOutput(); + } + } + + private: + std::shared_ptr mCCDBRequest; + std::unique_ptr mCalibrator; + bool mOneObjectPerRun; + bool mSaveToFile = false; + int mRunNoFromDH = 0; + uint32_t mSlotLenSec; + uint32_t mMinNumberOfEntries; + int32_t mMinAmplitudeSideA; + int32_t mMinAmplitudeSideC; + int32_t mMinSumOfAmplitude; +}; +} // namespace o2::calibration +#endif diff --git a/Detectors/FIT/FT0/macros/CMakeLists.txt b/Detectors/FIT/FT0/macros/CMakeLists.txt index c4ed27d2513ba..17491ca4962c1 100644 --- a/Detectors/FIT/FT0/macros/CMakeLists.txt +++ b/Detectors/FIT/FT0/macros/CMakeLists.txt @@ -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. +# 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) + +o2_add_test_root_macro(FT0readEventsPerBc.C + PUBLIC_LINK_LIBRARIES + O2::CCDB + O2::DataFormatsFT0 + LABELS ft0) diff --git a/Detectors/FIT/FT0/macros/FT0Misaligner.C b/Detectors/FIT/FT0/macros/FT0Misaligner.C index 9621d1a079bc9..16476ae3b8ccc 100644 --- a/Detectors/FIT/FT0/macros/FT0Misaligner.C +++ b/Detectors/FIT/FT0/macros/FT0Misaligner.C @@ -55,7 +55,7 @@ void FT0Misaligner(const std::string& ccdbHost = "http://ccdb-test.cern.ch:8080" std::string path = objectPath.empty() ? o2::base::DetectorNameConf::getAlignmentPath(detFT0) : objectPath; LOGP(info, "Storing alignment object on {}/{}", ccdbHost, path); o2::ccdb::CcdbApi api; - map metadata; // can be empty + std::map 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); diff --git a/Detectors/FIT/FT0/macros/FT0readEventsPerBc.C b/Detectors/FIT/FT0/macros/FT0readEventsPerBc.C new file mode 100644 index 0000000000000..c6afc86389b9b --- /dev/null +++ b/Detectors/FIT/FT0/macros/FT0readEventsPerBc.C @@ -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. + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include +#include +#endif + +#include "CCDB/CcdbApi.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "TH1F.h" +#include "DataFormatsFT0/EventsPerBc.h" +#include "Framework/Logger.h" +#include "CommonConstants/LHCConstants.h" + +std::unique_ptr hist; +std::unique_ptr canvas; + +void FT0readEventsPerBc(std::string ccdbUrl, long timestamp) +{ + o2::ccdb::CcdbApi ccdbApi; + ccdbApi.init(ccdbUrl); + const std::string ccdbPath = "FT0/Calib/EventsPerBc"; + std::map metadata; + + if (timestamp < 0) { + timestamp = o2::ccdb::getCurrentTimestamp(); + } + + std::unique_ptr events(ccdbApi.retrieveFromTFileAny(ccdbPath, metadata, timestamp)); + + if (!events) { + LOGP(fatal, "EventsPerBc object not found in {}/{} for timestamp {}.", ccdbUrl, ccdbPath, timestamp); + return; + } + + hist = std::make_unique("eventsPerBcHist", "Events per BC", o2::constants::lhc::LHCMaxBunches, 0, o2::constants::lhc::LHCMaxBunches - 1); + for (int idx = 0; idx < o2::constants::lhc::LHCMaxBunches; idx++) { + hist->Fill(idx, events->histogram[idx]); + } + canvas = std::make_unique(); + hist->Draw(); + canvas->Draw(); +} \ No newline at end of file diff --git a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CTFCoder.h b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CTFCoder.h index 4d749dbc90b42..41f11e303db67 100644 --- a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CTFCoder.h +++ b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CTFCoder.h @@ -34,10 +34,10 @@ namespace o2 namespace ft0 { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::FT0) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::FT0, 1.f, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode digits to buffer with CTF @@ -165,7 +165,9 @@ void CTFCoder::decompress(const CompressedDigits& cd, VDIG& digitVec, VCHAN& cha uint32_t firstEntry = 0, clCount = 0, chipCount = 0; o2::InteractionRecord ir(cd.header.firstBC, cd.header.firstOrbit); - + if (mBCShift && ir.toLong() >= mBCShift) { + ir -= mBCShift; + } for (uint32_t idig = 0; idig < cd.header.nTriggers; idig++) { // restore ROFRecord if (cd.orbitInc[idig]) { // non-0 increment => new orbit diff --git a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CollisionTimeRecoTask.h b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CollisionTimeRecoTask.h index ff3f8384f488d..9f6cd500b9e74 100644 --- a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CollisionTimeRecoTask.h +++ b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CollisionTimeRecoTask.h @@ -21,6 +21,7 @@ #include "DataFormatsFT0/FT0ChannelTimeCalibrationObject.h" #include "DataFormatsFT0/SpectraInfoObject.h" #include "DataFormatsFT0/SlewingCoef.h" +#include "DataFormatsFIT/DeadChannelMap.h" #include #include #include @@ -57,10 +58,16 @@ class CollisionTimeRecoTask LOG(info) << "Init for slewing calib object"; mCalibSlew = calibSlew->makeSlewingPlots(); }; + void SetDeadChannelMap(const o2::fit::DeadChannelMap* deadChannelMap) + { + LOG(info) << "Updated dead channel map for CollisionTimeRecoTask"; + mDeadChannelMap = deadChannelMap; + } float getTimeInPS(const o2::ft0::ChannelData& channelData); private: o2::ft0::TimeSpectraInfoObject const* mTimeCalibObject = nullptr; + const o2::fit::DeadChannelMap* mDeadChannelMap = nullptr; typename o2::ft0::SlewingCoef::SlewingPlots_t mCalibSlew{}; }; } // namespace ft0 diff --git a/Detectors/FIT/FT0/reconstruction/src/CollisionTimeRecoTask.cxx b/Detectors/FIT/FT0/reconstruction/src/CollisionTimeRecoTask.cxx index 7363cef57cf31..3e3ffe52671e9 100644 --- a/Detectors/FIT/FT0/reconstruction/src/CollisionTimeRecoTask.cxx +++ b/Detectors/FIT/FT0/reconstruction/src/CollisionTimeRecoTask.cxx @@ -67,6 +67,10 @@ RP CollisionTimeRecoTask::processDigit(const o2::ft0::Digit& digit, // Reference channels shouldn't participate in reco at all! continue; } + if (mDeadChannelMap && !mDeadChannelMap->isChannelAlive(channelData.ChId)) { + LOG(debug) << "Channel " << channelData.ChId << " is dead - discarding data"; + continue; + } const float timeInPS = getTimeInPS(channelData); if (ChannelFilterParam::Instance().checkAll(channelData)) { outChData.emplace_back(channelData.ChId, timeInPS, (float)channelData.QTCAmpl, channelData.ChainQTC); diff --git a/Detectors/FIT/FT0/simulation/src/Digitizer.cxx b/Detectors/FIT/FT0/simulation/src/Digitizer.cxx index aca012f1bc5a9..de432a85765c7 100644 --- a/Detectors/FIT/FT0/simulation/src/Digitizer.cxx +++ b/Detectors/FIT/FT0/simulation/src/Digitizer.cxx @@ -16,6 +16,13 @@ #include "CommonConstants/PhysicsConstants.h" #include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsFT0/LookUpTable.h" +#include "FT0Base/Constants.h" +#include +#include +#include +#include + #include "TMath.h" #include "TRandom.h" #include @@ -35,24 +42,84 @@ namespace o2::ft0 template 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); + float p0, p1, p2, p3, p4, p5, p6, p7; + p0 = 1.30853; + p1 = 0.516807; + p2 = 3.36714; + p3 = -1.01206; + p4 = 1.42832; + p5 = 1.1589; + p6 = 1.22019; + p7 = 0.426818; + + Double_t val = 0; + + if (x > p3) { + Double_t x1 = x - p3; + Double_t arg1 = (log(x1) - p0) / p1; + val += p2 * (1.0 / (x1 * p1 * sqrt(2 * TMath::Pi()))) * exp(-0.5 * arg1 * arg1); + } + + if (x > p7) { + Double_t x2 = x - p7; + Double_t arg2 = (log(x2) - p4) / p5; + val += p6 * (1.0 / (x2 * p5 * sqrt(2 * TMath::Pi()))) * exp(-0.5 * arg2 * arg2); + } + + return val; }; // 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; + float p0, p1, p2, p3, p4, p5, p6, p7; + p0 = 1.30853; + p1 = 0.516807; + p2 = 3.36714; + p3 = -1.01206; + p4 = 1.42832; + p5 = 1.1589; + p6 = 1.22019; + p7 = 0.426818; + Double_t val = 0; + + if (x > p3) { + Double_t x1 = x - p3; + Double_t z1 = (log(x1) - p0) / (sqrt(2) * p1); + val += p2 * 0.5 * (1 + TMath::Erf(z1)); // norm1 * CDF1 } - return -(exp(b * x) / b - exp(a * x) / a) / 7.8446501; + + if (x > p7) { + Double_t x2 = x - p7; + Double_t z2 = (log(x2) - p4) / (sqrt(2) * p5); + val += p6 * 0.5 * (1 + TMath::Erf(z2)); // norm2 * CDF2 + } + + return val; +}; +/* +// signal shape function +template +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) { @@ -249,8 +316,64 @@ void Digitizer::storeBC(BCCache& bc, if (bc.hits.empty()) { return; } + // Initialize mapping channelID -> PM hash and PM side (A/C) using FT0 LUT + static bool pmLutInitialized = false; + static std::array mChID2PMhash{}; + static std::map mMapPMhash2isAside; // hashed PM -> is A side + + if (!pmLutInitialized) { + std::map mapFEE2hash; // module name -> hashed PM id + uint8_t tcmHash = 0; + + const auto& lut = o2::ft0::SingleLUT::Instance().getVecMetadataFEE(); + auto lutSorted = lut; + std::sort(lutSorted.begin(), lutSorted.end(), + [](const auto& first, const auto& second) { return first.mModuleName < second.mModuleName; }); + + uint8_t binPos = 0; + for (const auto& lutEntry : lutSorted) { + const auto& moduleName = lutEntry.mModuleName; + const auto& moduleType = lutEntry.mModuleType; + const auto& strChID = lutEntry.mChannelID; + + auto [it, inserted] = mapFEE2hash.insert({moduleName, binPos}); + if (inserted) { + if (moduleName.find("PMA") != std::string::npos) { + mMapPMhash2isAside.insert({binPos, true}); + } else if (moduleName.find("PMC") != std::string::npos) { + mMapPMhash2isAside.insert({binPos, false}); + } + ++binPos; + } + + if (std::regex_match(strChID, std::regex("^[0-9]{1,3}$"))) { + int chID = std::stoi(strChID); + if (chID < o2::ft0::Constants::sNCHANNELS_PM) { + mChID2PMhash[chID] = mapFEE2hash[moduleName]; + } else { + LOG(fatal) << "Incorrect LUT entry: chID " << strChID << " | " << moduleName; + } + } else if (moduleType != "TCM") { + LOG(fatal) << "Non-TCM module w/o numerical chID: chID " << strChID << " | " << moduleName; + } else { // TCM + tcmHash = mapFEE2hash[moduleName]; + } + } + + pmLutInitialized = true; + } + 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 sum_A_ampl = 0, sum_C_ampl = 0; + int nPMTs = mGeometry.NCellsA * 4 + mGeometry.NCellsC * 4; + std::vector sum_ampl_ipmt(nPMTs, 0); + // Per-PM summed charge (like in digits2trgFT0) + std::map mapPMhash2sumAmpl; + for (const auto& entry : mMapPMhash2isAside) { + mapPMhash2sumAmpl.insert({entry.first, 0}); + } + int vertex_time; const auto& params = FT0DigParam::Instance(); int first = digitsCh.size(), nStored = 0; @@ -297,6 +420,10 @@ void Digitizer::storeBC(BCCache& bc, if (is_time_in_signal_gate) { chain |= (1 << o2::ft0::ChannelData::EEventDataBit::kIsCFDinADCgate); chain |= (1 << o2::ft0::ChannelData::EEventDataBit::kIsEventInTVDC); + // Sum channel charge per PM (similar logic as in digits2trgFT0) + if (ipmt < o2::ft0::Constants::sNCHANNELS_PM) { + mapPMhash2sumAmpl[mChID2PMhash[static_cast(ipmt)]] += static_cast(amp); + } } digitsCh.emplace_back(ipmt, smeared_time, int(amp), chain); nStored++; @@ -308,6 +435,8 @@ void Digitizer::storeBC(BCCache& bc, continue; } + sum_ampl_ipmt[ipmt] += amp; + if (is_A_side) { n_hit_A++; summ_ampl_A += amp; @@ -318,17 +447,47 @@ void Digitizer::storeBC(BCCache& bc, mean_time_C += smeared_time; } } + + for (size_t i = 0; i < sum_ampl_ipmt.size(); i++) { + sum_ampl_ipmt[i] = sum_ampl_ipmt[i] >> 3; + if (i < 4 * mGeometry.NCellsA) { + sum_A_ampl += sum_ampl_ipmt[i]; + } else { + sum_C_ampl += sum_ampl_ipmt[i]; + } + } + + // Sum over PMs (using per-PM map) for debug/monitoring + int sum_PM_ampl_debug = 0; + int sum_PM_ampl_A_debug = 0; + int sum_PM_ampl_C_debug = 0; + for (const auto& entry : mapPMhash2sumAmpl) { + int pmAmpl = (entry.second >> 3); + sum_PM_ampl_debug += pmAmpl; + auto itSide = mMapPMhash2isAside.find(entry.first); + if (itSide != mMapPMhash2isAside.end()) { + if (itSide->second) { + sum_PM_ampl_A_debug += pmAmpl; + } else { + sum_PM_ampl_C_debug += pmAmpl; + } + } + } + LOG(debug) << "Sum PM amplitude (LUT-based): total=" << sum_PM_ampl_debug + << " A-side=" << sum_PM_ampl_A_debug + << " C-side=" << sum_PM_ampl_C_debug; + 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 >= params.mtrg_central_trh; - is_SemiCentral = summ_ampl_A + summ_ampl_C >= params.mtrg_semicentral_trh; + is_Central = sum_PM_ampl_A_debug + sum_PM_ampl_C_debug >= 2 * params.mtrg_central_trh; + is_SemiCentral = sum_PM_ampl_A_debug + sum_PM_ampl_C_debug >= 2 * params.mtrg_semicentral_trh && !is_Central; uint32_t amplA = is_A ? summ_ampl_A * 0.125 : -5000; // sum amplitude A side / 8 (hardware) uint32_t amplC = is_C ? summ_ampl_C * 0.125 : -5000; // sum amplitude C side / 8 (hardware) int timeA = is_A ? mean_time_A / n_hit_A : -5000; // average time A side int timeC = is_C ? mean_time_C / n_hit_C : -5000; // 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); + isVertex = is_A && is_C && (vertex_time > -params.mTime_trg_vertex_gate && vertex_time < params.mTime_trg_vertex_gate); LOG(debug) << " A " << is_A << " timeA " << timeA << " mean_time_A " << mean_time_A << " n_hit_A " << n_hit_A << " C " << is_C << " timeC " << timeC << " mean_time_C " << mean_time_C << " n_hit_C " << n_hit_C << " vertex_time " << vertex_time; Triggers triggers; bool isLaser = false; diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyDecoderSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyDecoderSpec.h index 4f8e8b5e9be63..d6009accfa45b 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyDecoderSpec.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyDecoderSpec.h @@ -28,7 +28,7 @@ namespace ft0 class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity); + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -41,7 +41,7 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt); } // namespace ft0 } // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyEncoderSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyEncoderSpec.h index 8fd597af8629d..a1b3714fdbb26 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyEncoderSpec.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyEncoderSpec.h @@ -28,7 +28,7 @@ namespace ft0 class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR); + EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -42,7 +42,7 @@ class EntropyEncoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); } // namespace ft0 } // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataProcessDPLSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataProcessDPLSpec.h deleted file mode 100644 index 7b7e98d50368e..0000000000000 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataProcessDPLSpec.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file FT0DataProcessDPLSpec.h - -#ifndef O2_FT0DATAPROCESSDPLSPEC_H -#define O2_FT0DATAPROCESSDPLSPEC_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 "FT0Raw/DigitBlockFT0.h" -#include "DataFormatsFT0/Digit.h" -#include "DataFormatsFT0/ChannelData.h" - -#include -#include -#include - -using namespace o2::framework; - -namespace o2 -{ -namespace ft0 -{ - -class FT0DataProcessDPLSpec : public Task -{ - public: - FT0DataProcessDPLSpec(bool dumpEventBlocks) : mDumpEventBlocks(dumpEventBlocks) {} - ~FT0DataProcessDPLSpec() override = default; - void init(InitContext& ic) final; - void run(ProcessingContext& pc) final; - - private: - bool mDumpEventBlocks; - - o2::header::DataOrigin mOrigin = o2::header::gDataOriginFT0; -}; - -framework::DataProcessorSpec getFT0DataProcessDPLSpec(bool dumpProcessor); - -} // namespace ft0 -} // namespace o2 - -#endif /* O2_FT0DATAPROCESSDPL_H */ diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataReaderDPLSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataReaderDPLSpec.h deleted file mode 100644 index 9074f4f7f0f34..0000000000000 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataReaderDPLSpec.h +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file FT0DataReaderDPLSpec.h - -#ifndef O2_FT0DATAREADERDPLSPEC_H -#define O2_FT0DATAREADERDPLSPEC_H -#include "DataFormatsFT0/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 "Framework/InputRecordWalker.h" -#include -#include -#include -#include "CommonUtils/VerbosityConfig.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace ft0 -{ -template -class FT0DataReaderDPLSpec : public Task -{ - public: - FT0DataReaderDPLSpec(const RawReader& rawReader) : mRawReader(rawReader) {} - FT0DataReaderDPLSpec() = default; - ~FT0DataReaderDPLSpec() override = default; - typedef RawReader RawReader_t; - void init(InitContext& ic) final { o2::ft0::SingleLUT::Instance().printFullMap(); } - 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 - { - static size_t contDeadBeef = 0; // number of times 0xDEADBEEF was seen continuously - std::vector 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(ref); - auto payloadSize = DataRefUtils::getPayloadSize(ref); - if (payloadSize == 0) { - auto maxWarn = o2::conf::VerbosityConfig::Instance().maxWarnDeadBeef; - if (++contDeadBeef <= maxWarn) { - LOGP(alarm, "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, payloadSize, - contDeadBeef == maxWarn ? fmt::format(". {} such inputs in row received, stopping reporting", contDeadBeef) : ""); - } - mRawReader.makeSnapshot(pc); // send empty output - return; - } - } - contDeadBeef = 0; // if good data, reset the counter - } - std::vector 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 = reinterpret_cast(it.raw()); - gsl::span payload(it.data(), it.size()); - mRawReader.process(payload, o2::raw::RDHUtils::getLinkID(rdhPtr), o2::raw::RDHUtils::getEndPointID(rdhPtr)); - } - LOG(info) << "Pages: " << count; - mRawReader.accumulateDigits(); - mRawReader.makeSnapshot(pc); - mRawReader.clear(); - } - RawReader_t mRawReader; -}; - -template -framework::DataProcessorSpec getFT0DataReaderDPLSpec(const RawReader& rawReader, bool askSTFDist) -{ - LOG(info) << "DataProcessorSpec initDataProcSpec() for RawReaderFT0"; - std::vector outputSpec; - RawReader::prepareOutputSpec(outputSpec); - std::vector inputSpec{{"STF", ConcreteDataTypeMatcher{o2::header::gDataOriginFT0, "RAWDATA"}, Lifetime::Timeframe}}; - if (askSTFDist) { - inputSpec.emplace_back("STFDist", "FLP", "DISTSUBTIMEFRAME", 0, Lifetime::Timeframe); - } - return DataProcessorSpec{ - "ft0-datareader-dpl", - inputSpec, - outputSpec, - adaptFromTask>(rawReader), - Options{}}; -} - -} // namespace ft0 -} // namespace o2 - -#endif /* O2_FT0DATAREADERDPL_H */ diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/RawReaderFT0.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/RawReaderFT0.h deleted file mode 100644 index f7729394db652..0000000000000 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/RawReaderFT0.h +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -//file RawReaderFT0.h class for RAW data reading -// -// Artur.Furs -// afurs@cern.ch -// -//Main purpuse is to decode FT0 data blocks and push them to DigitBlockFT0 for proccess -//TODO: prepare wrappers for containers with digits and combine classes below into one template class? -#ifndef ALICEO2_FIT_RAWREADERFT0_H_ -#define ALICEO2_FIT_RAWREADERFT0_H_ -#include -#include -#include -#include "FT0Raw/RawReaderFT0Base.h" - -#include "DataFormatsFT0/Digit.h" -#include "DataFormatsFT0/ChannelData.h" - -#include "Framework/ProcessingContext.h" -#include "Framework/DataAllocator.h" -#include "Framework/OutputSpec.h" -#include - -namespace o2 -{ -namespace ft0 -{ -//Normal TCM mode -template -class RawReaderFT0 : public RawReaderFT0BaseNorm -{ - public: - RawReaderFT0(bool dumpData) : mDumpData(dumpData) {} - RawReaderFT0(const RawReaderFT0&) = default; - - RawReaderFT0() = default; - ~RawReaderFT0() = default; - static constexpr bool sUseTrgInput = useTrgInput; - void clear() - { - mVecDigits.clear(); - if constexpr (sUseTrgInput) { - mVecTriggerInput.clear(); - } - mVecChannelData.clear(); - } - void accumulateDigits() - { - 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); - } - } - static void prepareOutputSpec(std::vector& outputSpec) - { - 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}, mVecDigits); - pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "DIGITSCH", 0}, mVecChannelData); - if constexpr (sUseTrgInput) { - pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "TRIGGERINPUT", 0}, mVecTriggerInput); - } - } - bool mDumpData; - std::vector mVecDigits; - std::vector mVecTriggerInput; - std::vector mVecChannelData; -}; - -//Extended TCM mode (additional raw data struct) -template -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() - { - mVecDigits.clear(); - mVecChannelData.clear(); - mVecTrgExt.clear(); - if constexpr (sUseTrgInput) { - mVecTriggerInput.clear(); - } - } - void accumulateDigits() - { - 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(mVecDigits, mVecChannelData, mVecTrgExt); - } - } - static void prepareOutputSpec(std::vector& outputSpec) - { - 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}, mVecDigits); - pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "DIGITSCH", 0}, mVecChannelData); - pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "DIGITSTRGEXT", 0}, mVecTrgExt); - if constexpr (sUseTrgInput) { - pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "TRIGGERINPUT", 0}, mVecTriggerInput); - } - } - bool mDumpData; - std::vector mVecDigits; - std::vector mVecChannelData; - std::vector mVecTrgExt; - std::vector mVecTriggerInput; -}; - -} // namespace ft0 -} // namespace o2 - -#endif diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecoWorkflow.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecoWorkflow.h index 3c6e4599a250c..6de23a1c66bfd 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecoWorkflow.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecoWorkflow.h @@ -20,7 +20,7 @@ namespace o2 { namespace ft0 { -framework::WorkflowSpec getRecoWorkflow(bool useMC, std::string ccdbpath, bool useTimeOffsetCalib, bool useSlewingCalib, bool disableRootInp, bool disableRootOut); +framework::WorkflowSpec getRecoWorkflow(bool useMC, std::string ccdbpath, bool useTimeOffsetCalib, bool useSlewingCalib, bool disableRootInp, bool disableRootOut, bool useDeadChannelMap = true); } // namespace ft0 } // namespace o2 #endif diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/ReconstructionSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/ReconstructionSpec.h index 1c671352e6ba7..307b2109fe35f 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/ReconstructionSpec.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/ReconstructionSpec.h @@ -34,7 +34,7 @@ class ReconstructionDPL : public Task static constexpr int NCHANNELS = o2::ft0::Geometry::Nchannels; public: - ReconstructionDPL(bool useMC, const std::string& ccdbpath, bool useTimeOffsetCalib, bool useSlewingCalib) : mUseMC(useMC), mCCDBpath(ccdbpath), mUseTimeOffsetCalib(useTimeOffsetCalib), mUseSlewingCalib(useSlewingCalib) {} + ReconstructionDPL(bool useMC, const std::string& ccdbpath, bool useTimeOffsetCalib, bool useSlewingCalib, bool useDeadChannelMap) : mUseMC(useMC), mCCDBpath(ccdbpath), mUseTimeOffsetCalib(useTimeOffsetCalib), mUseSlewingCalib(useSlewingCalib), mUseDeadChannelMap(useDeadChannelMap) {} ~ReconstructionDPL() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -46,6 +46,8 @@ class ReconstructionDPL : public Task bool mUpdateCCDB = true; bool mUseTimeOffsetCalib = true; bool mUseSlewingCalib = true; + bool mUseDeadChannelMap = true; + bool mUpdateDeadChannelMap = true; const std::string mCCDBpath = o2::base::NameConf::getCCDBServer(); std::vector mRecPoints; std::vector mRecChData; @@ -55,7 +57,7 @@ class ReconstructionDPL : public Task }; /// create a processor spec -framework::DataProcessorSpec getReconstructionSpec(bool useMC = false, const std::string ccdbpath = "http://alice-ccdb.cern.ch", bool useTimeOffsetCalib = true, bool useSlewingCalib = true); +framework::DataProcessorSpec getReconstructionSpec(bool useMC = false, const std::string ccdbpath = "http://alice-ccdb.cern.ch", bool useTimeOffsetCalib = true, bool useSlewingCalib = true, bool useDeadChannelMap = true); } // namespace ft0 } // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/src/EntropyDecoderSpec.cxx b/Detectors/FIT/FT0/workflow/src/EntropyDecoderSpec.cxx index 65d3585350888..97ea337705fee 100644 --- a/Detectors/FIT/FT0/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/FIT/FT0/workflow/src/EntropyDecoderSpec.cxx @@ -24,12 +24,12 @@ namespace o2 { namespace ft0 { - -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); mCTFCoder.setVerbosity(verbosity); + mCTFCoder.setSupportBCShifts(true); mCTFCoder.setDictBinding("ctfdict_FT0"); } @@ -73,7 +73,7 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"digits"}, "FT0", "DIGITSBC", 0, Lifetime::Timeframe}, @@ -82,16 +82,18 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) std::vector inputs; inputs.emplace_back("ctf_FT0", "FT0", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_FT0", "FT0", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FT0/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_FT0", "FT0", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FT0/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ "ft0-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace ft0 } // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/src/EntropyEncoderSpec.cxx b/Detectors/FIT/FT0/workflow/src/EntropyEncoderSpec.cxx index 81bdc2e729bb4..7be6618a61103 100644 --- a/Detectors/FIT/FT0/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/FIT/FT0/workflow/src/EntropyEncoderSpec.cxx @@ -25,8 +25,7 @@ namespace o2 { namespace ft0 { - -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR) { mTimer.Stop(); mTimer.Reset(); @@ -70,12 +69,15 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("digits", "FT0", "DIGITSBC", 0, Lifetime::Timeframe); inputs.emplace_back("channels", "FT0", "DIGITSCH", 0, Lifetime::Timeframe); - inputs.emplace_back("ctfdict", "FT0", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FT0/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "FT0", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FT0/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -83,13 +85,11 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR) "ft0-entropy-encoder", inputs, Outputs{{"FT0", "CTFDATA", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace ft0 } // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/src/FT0DataProcessDPLSpec.cxx b/Detectors/FIT/FT0/workflow/src/FT0DataProcessDPLSpec.cxx deleted file mode 100644 index d7a7a689d402f..0000000000000 --- a/Detectors/FIT/FT0/workflow/src/FT0DataProcessDPLSpec.cxx +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file FT0DataProcessDPLSpec.cxx - -#include "FT0Workflow/FT0DataProcessDPLSpec.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace ft0 -{ -using namespace std; -void FT0DataProcessDPLSpec::init(InitContext& ic) -{ -} - -void FT0DataProcessDPLSpec::run(ProcessingContext& pc) -{ - LOG(info) << "FT0DataProcessDPLSpec running..."; - auto vecDigits = pc.inputs().get>("digits"); - auto vecChannelData = pc.inputs().get>("digch"); - if (mDumpEventBlocks) { - DigitBlockFT0::print(vecDigits, vecChannelData); - } -} - -DataProcessorSpec getFT0DataProcessDPLSpec(bool dumpProcessor) -{ - std::vector inputSpec; - inputSpec.emplace_back("digits", o2::header::gDataOriginFT0, "DIGITSBC", 0, Lifetime::Timeframe); - inputSpec.emplace_back("digch", o2::header::gDataOriginFT0, "DIGITSCH", 0, Lifetime::Timeframe); - LOG(info) << "DataProcessorSpec getFT0DataProcessDPLSpec"; - return DataProcessorSpec{ - "ft0-dataprocess-dpl-flp", - inputSpec, - Outputs{}, - AlgorithmSpec{adaptFromTask(dumpProcessor)}, - Options{}}; -} - -} // namespace ft0 -} // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/src/FT0Workflow.cxx b/Detectors/FIT/FT0/workflow/src/FT0Workflow.cxx deleted file mode 100644 index 156feb7dd3e2f..0000000000000 --- a/Detectors/FIT/FT0/workflow/src/FT0Workflow.cxx +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file FT0Workflow.cxx - -#include "FT0Workflow/FT0Workflow.h" -#include "FT0Workflow/FT0DataProcessDPLSpec.h" -#include "FT0Workflow/FT0DataReaderDPLSpec.h" -#include "FT0Workflow/FT0DigitWriterSpec.h" -#include "FT0Workflow/RawReaderFT0.h" -namespace o2 -{ -namespace ft0 -{ - -framework::WorkflowSpec getFT0Workflow(bool isExtendedMode, bool useProcess, - bool dumpProcessor, bool dumpReader, - bool disableRootOut, bool askSTFDist) -{ - LOG(info) << "framework::WorkflowSpec getFT0Workflow"; - framework::WorkflowSpec specs; - if (isExtendedMode) { - specs.emplace_back(o2::ft0::getFT0DataReaderDPLSpec(RawReaderFT0ext{dumpReader}, askSTFDist)); - } else { - specs.emplace_back(o2::ft0::getFT0DataReaderDPLSpec(RawReaderFT0{dumpReader}, askSTFDist)); - } - if (useProcess) { - specs.emplace_back(o2::ft0::getFT0DataProcessDPLSpec(dumpProcessor)); - } - if (!disableRootOut) { - specs.emplace_back(o2::ft0::getFT0DigitWriterSpec(false, false)); - } - return specs; -} - -} // namespace ft0 -} // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/src/RecoWorkflow.cxx b/Detectors/FIT/FT0/workflow/src/RecoWorkflow.cxx index 247158164ac3b..2231011febd7f 100644 --- a/Detectors/FIT/FT0/workflow/src/RecoWorkflow.cxx +++ b/Detectors/FIT/FT0/workflow/src/RecoWorkflow.cxx @@ -22,13 +22,13 @@ namespace o2 namespace ft0 { -framework::WorkflowSpec getRecoWorkflow(bool useMC, std::string ccdbpath, bool useTimeOffsetCalib, bool useSlewingCalib, bool disableRootInp, bool disableRootOut) +framework::WorkflowSpec getRecoWorkflow(bool useMC, std::string ccdbpath, bool useTimeOffsetCalib, bool useSlewingCalib, bool disableRootInp, bool disableRootOut, bool useDeadChannelMap) { framework::WorkflowSpec specs; if (!disableRootInp) { specs.emplace_back(o2::ft0::getDigitReaderSpec(useMC)); } - specs.emplace_back(o2::ft0::getReconstructionSpec(useMC, ccdbpath, useTimeOffsetCalib, useSlewingCalib)); + specs.emplace_back(o2::ft0::getReconstructionSpec(useMC, ccdbpath, useTimeOffsetCalib, useSlewingCalib, useDeadChannelMap)); 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 40bc96ebca58e..bc5217c8d7471 100644 --- a/Detectors/FIT/FT0/workflow/src/ReconstructionSpec.cxx +++ b/Detectors/FIT/FT0/workflow/src/ReconstructionSpec.cxx @@ -44,6 +44,7 @@ void ReconstructionDPL::init(InitContext& ic) LOG(info) << "FT0 param mMinRMS: " << CalibParam::Instance().mMinRMS; LOG(info) << "FT0 param mMaxSigma: " << CalibParam::Instance().mMaxSigma; LOG(info) << "FT0 param mMaxDiffMean: " << CalibParam::Instance().mMaxDiffMean; + LOG(info) << "FT0 dead channel map will be applied " << mUseDeadChannelMap; } void ReconstructionDPL::run(ProcessingContext& pc) @@ -69,6 +70,12 @@ void ReconstructionDPL::run(ProcessingContext& pc) mReco.SetSlewingCalibObject(slewingCalibObject.get()); } + if (mUseDeadChannelMap && mUpdateDeadChannelMap) { + LOG(debug) << "Applying dead channel map"; + auto deadChannelMap = pc.inputs().get("deadChannelMap"); + mReco.SetDeadChannelMap(deadChannelMap.get()); + } + mRecPoints.reserve(digits.size()); mRecChData.reserve(channels.size()); mReco.processTF(digits, channels, mRecPoints, mRecChData); @@ -91,6 +98,11 @@ void ReconstructionDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) mUseSlewingCalib = false; // upload only once, slewing should be stable during the run return; } + if (matcher == ConcreteDataMatcher("FT0", "DeadChannelMap", 0)) { + LOG(debug) << "New DeadChannelMap is uploaded"; + mUpdateDeadChannelMap = false; + return; + } } void ReconstructionDPL::endOfStream(EndOfStreamContext& ec) @@ -99,12 +111,13 @@ void ReconstructionDPL::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getReconstructionSpec(bool useMC, const std::string ccdbpath, bool useTimeOffsetCalib, bool useSlewingCalib) +DataProcessorSpec getReconstructionSpec(bool useMC, const std::string ccdbpath, bool useTimeOffsetCalib, bool useSlewingCalib, bool useDeadChannelMap) { std::vector inputSpec; std::vector outputSpec; inputSpec.emplace_back("digits", o2::header::gDataOriginFT0, "DIGITSBC", 0, Lifetime::Timeframe); inputSpec.emplace_back("digch", o2::header::gDataOriginFT0, "DIGITSCH", 0, Lifetime::Timeframe); + if (useMC) { LOG(info) << "Currently Reconstruction does not consume and provide MC truth"; inputSpec.emplace_back("labels", o2::header::gDataOriginFT0, "DIGITSMCTR", 0, Lifetime::Timeframe); @@ -121,6 +134,11 @@ DataProcessorSpec getReconstructionSpec(bool useMC, const std::string ccdbpath, ccdbParamSpec("FT0/Calib/SlewingCoef")); } + if (useDeadChannelMap) { + LOG(info) << "Dead channel map will be applied during reconstruction"; + inputSpec.emplace_back("deadChannelMap", o2::header::gDataOriginFT0, "DeadChannelMap", 0, Lifetime::Condition, ccdbParamSpec("FT0/Calib/DeadChannelMap")); + } + outputSpec.emplace_back(o2::header::gDataOriginFT0, "RECPOINTS", 0, Lifetime::Timeframe); outputSpec.emplace_back(o2::header::gDataOriginFT0, "RECCHDATA", 0, Lifetime::Timeframe); @@ -128,7 +146,7 @@ DataProcessorSpec getReconstructionSpec(bool useMC, const std::string ccdbpath, "ft0-reconstructor", inputSpec, outputSpec, - AlgorithmSpec{adaptFromTask(useMC, ccdbpath, useTimeOffsetCalib, useSlewingCalib)}, + AlgorithmSpec{adaptFromTask(useMC, ccdbpath, useTimeOffsetCalib, useSlewingCalib, useDeadChannelMap)}, Options{}}; } diff --git a/Detectors/FIT/FT0/workflow/src/entropy-encoder-workflow.cxx b/Detectors/FIT/FT0/workflow/src/entropy-encoder-workflow.cxx index 6a98bbdafd53b..144d27abeda9c 100644 --- a/Detectors/FIT/FT0/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/FIT/FT0/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "none", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -37,6 +38,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::ft0::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"))); + wf.emplace_back(o2::ft0::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/FIT/FT0/workflow/src/ft0-reco-workflow.cxx b/Detectors/FIT/FT0/workflow/src/ft0-reco-workflow.cxx index 3e6a6bf5da090..ab39068aedb38 100644 --- a/Detectors/FIT/FT0/workflow/src/ft0-reco-workflow.cxx +++ b/Detectors/FIT/FT0/workflow/src/ft0-reco-workflow.cxx @@ -41,7 +41,8 @@ void customize(std::vector& workflowOptions) {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}, {"disable-time-offset-calib", o2::framework::VariantType::Bool, false, {"disable timeoffset calibration"}}, {"disable-slewing-calib", o2::framework::VariantType::Bool, false, {"disable slewing calibration"}}, - {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + {"disable-dead-channel-map", VariantType::Bool, false, {"disable dead channel map"}}}; o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } @@ -64,9 +65,10 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto disableRootOut = configcontext.options().get("disable-root-output"); const auto useTimeOffsetCalib = !configcontext.options().get("disable-time-offset-calib"); const auto useSlewingCalib = !configcontext.options().get("disable-slewing-calib"); + const auto useDeadChannelMap = !configcontext.options().get("disable-dead-channel-map"); LOG(info) << "WorkflowSpec getRecoWorkflow useMC " << useMC << " CCDB " << ccdbpath; - auto wf = o2::ft0::getRecoWorkflow(useMC, ccdbpath, useTimeOffsetCalib, useSlewingCalib, disableRootInp, disableRootOut); + auto wf = o2::ft0::getRecoWorkflow(useMC, ccdbpath, useTimeOffsetCalib, useSlewingCalib, disableRootInp, disableRootOut, useDeadChannelMap); // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit o2::raw::HBFUtilsInitializer hbfIni(configcontext, wf); diff --git a/Detectors/FIT/FV0/calibration/macros/readChannelTimeOffsetFV0CalibObjectFromCCDB.C b/Detectors/FIT/FV0/calibration/macros/readChannelTimeOffsetFV0CalibObjectFromCCDB.C index 06b86e3c5015d..3f42c0219b101 100644 --- a/Detectors/FIT/FV0/calibration/macros/readChannelTimeOffsetFV0CalibObjectFromCCDB.C +++ b/Detectors/FIT/FV0/calibration/macros/readChannelTimeOffsetFV0CalibObjectFromCCDB.C @@ -22,8 +22,8 @@ int readChannelTimeOffsetFV0CalibObjectFromCCDB(const std::string url = "http:// { o2::ccdb::CcdbApi api; api.init(url); - map metadata; - map headers; + std::map metadata; + std::map headers; auto retrieved = api.retrieveFromTFileAny("FV0/Calib/ChannelTimeOffset", metadata, -1, &headers); std::cout << "--- HEADERS ---" << std::endl; diff --git a/Detectors/FIT/FV0/macros/FV0Misaligner.C b/Detectors/FIT/FV0/macros/FV0Misaligner.C index 88f7a0b82b8b3..61be50b48dede 100644 --- a/Detectors/FIT/FV0/macros/FV0Misaligner.C +++ b/Detectors/FIT/FV0/macros/FV0Misaligner.C @@ -54,7 +54,7 @@ void FV0Misaligner(const std::string& ccdbHost = "http://ccdb-test.cern.ch:8080" std::string path = objectPath.empty() ? o2::base::DetectorNameConf::getAlignmentPath(detFV0) : objectPath; LOGP(info, "Storing alignment object on {}/{}", ccdbHost, path); o2::ccdb::CcdbApi api; - map metadata; // can be empty + std::map 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); diff --git a/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/BaseRecoTask.h b/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/BaseRecoTask.h index 12d89b82a13cc..c5cb5b0da6d05 100644 --- a/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/BaseRecoTask.h +++ b/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/BaseRecoTask.h @@ -18,6 +18,7 @@ #include "DataFormatsFV0/ChannelData.h" #include "DataFormatsFV0/RecPoints.h" #include "DataFormatsFV0/FV0ChannelTimeCalibrationObject.h" +#include "DataFormatsFIT/DeadChannelMap.h" #include namespace o2 @@ -33,14 +34,15 @@ class BaseRecoTask ~BaseRecoTask() = default; o2::fv0::RecPoints process(o2::fv0::Digit const& bcd, gsl::span inChData, - gsl::span outChData); + std::vector& outChData); void FinishTask(); void SetChannelOffset(o2::fv0::FV0ChannelTimeCalibrationObject const* caliboffsets) { mCalibOffset = caliboffsets; }; + void SetDeadChannelMap(o2::fit::DeadChannelMap const* deadChannelMap) { mDeadChannelMap = deadChannelMap; } int getOffset(int channel); private: o2::fv0::FV0ChannelTimeCalibrationObject const* mCalibOffset = nullptr; - + o2::fit::DeadChannelMap const* mDeadChannelMap = nullptr; ClassDefNV(BaseRecoTask, 3); }; } // namespace fv0 diff --git a/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/CTFCoder.h b/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/CTFCoder.h index cbec444ef11be..082fbd93a705a 100644 --- a/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/CTFCoder.h +++ b/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/CTFCoder.h @@ -30,10 +30,10 @@ namespace o2 namespace fv0 { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::FV0) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::FV0, 1.f, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode digits to buffer with CTF @@ -168,7 +168,9 @@ void CTFCoder::decompress(const CompressedDigits& cd, VDIG& digitVec, VCHAN& cha uint32_t firstEntry = 0, clCount = 0, chipCount = 0; o2::InteractionRecord ir(cd.header.firstBC, cd.header.firstOrbit); - + if (mBCShift && ir.toLong() >= mBCShift) { + ir -= mBCShift; + } for (uint32_t idig = 0; idig < cd.header.nTriggers; idig++) { // restore ROFRecord if (cd.orbitInc[idig]) { // non-0 increment => new orbit diff --git a/Detectors/FIT/FV0/reconstruction/src/BaseRecoTask.cxx b/Detectors/FIT/FV0/reconstruction/src/BaseRecoTask.cxx index 8a217232592df..8032220f8996d 100644 --- a/Detectors/FIT/FV0/reconstruction/src/BaseRecoTask.cxx +++ b/Detectors/FIT/FV0/reconstruction/src/BaseRecoTask.cxx @@ -27,7 +27,7 @@ using RP = o2::fv0::RecPoints; RP BaseRecoTask::process(o2::fv0::Digit const& bcd, gsl::span inChData, - gsl::span outChData) + std::vector& outChData) { LOG(debug) << "Running reconstruction on new event"; @@ -44,22 +44,27 @@ RP BaseRecoTask::process(o2::fv0::Digit const& bcd, int nch = inChData.size(); for (int ich = 0; ich < nch; ich++) { LOG(debug) << " channel " << ich << " / " << nch; + if (mDeadChannelMap && !mDeadChannelMap->isChannelAlive(inChData[ich].ChId)) { + LOG(debug) << "Channel " << ich << " is dead - discarding data"; + continue; + } int offsetChannel = getOffset(int(inChData[ich].ChId)); - outChData[ich] = o2::fv0::ChannelDataFloat{inChData[ich].ChId, - (inChData[ich].CFDTime - offsetChannel) * DigitizationConstant::TIME_PER_TDCCHANNEL, - (float)inChData[ich].QTCAmpl, - inChData[ich].ChainQTC}; + outChData.emplace_back(o2::fv0::ChannelDataFloat{inChData[ich].ChId, + (inChData[ich].CFDTime - offsetChannel) * DigitizationConstant::TIME_PER_TDCCHANNEL, + (float)inChData[ich].QTCAmpl, + inChData[ich].ChainQTC}); + const auto& currentOutCh = outChData.back(); // Conditions for reconstructing collision time (3 variants: first, average-relaxed and average-tight) - if (outChData[ich].charge > FV0DigParam::Instance().chargeThrForMeanTime) { - sideAtimeFirst = std::min(static_cast(sideAtimeFirst), outChData[ich].time); + if (currentOutCh.charge > FV0DigParam::Instance().chargeThrForMeanTime) { + sideAtimeFirst = std::min(static_cast(sideAtimeFirst), currentOutCh.time); if (inChData[ich].areAllFlagsGood()) { - if (std::abs(outChData[ich].time) < FV0DigParam::Instance().mTimeThresholdForReco) { - sideAtimeAvg += outChData[ich].time; + if (std::abs(currentOutCh.time) < FV0DigParam::Instance().mTimeThresholdForReco) { + sideAtimeAvg += currentOutCh.time; ndigitsA++; } - if (outChData[ich].charge > FV0DigParam::Instance().mAmpThresholdForReco && std::abs(outChData[ich].time) < FV0DigParam::Instance().mTimeThresholdForReco) { - sideAtimeAvgSelected += outChData[ich].time; + if (currentOutCh.charge > FV0DigParam::Instance().mAmpThresholdForReco && std::abs(currentOutCh.time) < FV0DigParam::Instance().mTimeThresholdForReco) { + sideAtimeAvgSelected += currentOutCh.time; ndigitsASelected++; } } diff --git a/Detectors/FIT/FV0/simulation/include/FV0Simulation/Digitizer.h b/Detectors/FIT/FV0/simulation/include/FV0Simulation/Digitizer.h index 6956d8126ce53..b97893822c9d8 100644 --- a/Detectors/FIT/FV0/simulation/include/FV0Simulation/Digitizer.h +++ b/Detectors/FIT/FV0/simulation/include/FV0Simulation/Digitizer.h @@ -14,6 +14,7 @@ #include "CommonDataFormat/InteractionRecord.h" #include "DataFormatsFV0/Digit.h" +#include "DataFormatsFIT/DeadChannelMap.h" #include "DataFormatsFV0/ChannelData.h" #include "DataFormatsFV0/MCLabel.h" #include "FV0Simulation/Detector.h" @@ -51,6 +52,7 @@ class Digitizer void setEventId(Int_t id) { mEventId = id; } void setSrcId(Int_t id) { mSrcId = id; } void setInteractionRecord(const InteractionTimeRecord& ir) { mIntRecord = ir; } + void setDeadChannelMap(o2::fit::DeadChannelMap const* deadChannelMap) { mDeadChannelMap = deadChannelMap; }; void process(const std::vector& hits, std::vector& digitsBC, std::vector& digitsCh, std::vector& digitsTrig, @@ -132,6 +134,8 @@ class Digitizer BCCache mLastBCCache; // buffer for the last BC std::array mCfdStartIndex; // start indices for the CFD detector + o2::fit::DeadChannelMap const* mDeadChannelMap = nullptr; + /// 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(int& startIndex, const ChannelDigitF& pulseLast, const ChannelDigitF& pulse) const; diff --git a/Detectors/FIT/FV0/simulation/include/FV0Simulation/FV0DigParam.h b/Detectors/FIT/FV0/simulation/include/FV0Simulation/FV0DigParam.h index 383fa4cb494c1..6462323a279b7 100644 --- a/Detectors/FIT/FV0/simulation/include/FV0Simulation/FV0DigParam.h +++ b/Detectors/FIT/FV0/simulation/include/FV0Simulation/FV0DigParam.h @@ -69,6 +69,10 @@ struct FV0DigParam : o2::conf::ConfigurableParamHelper { uint8_t defaultChainQtc = 0x48; // only 2 flags are set by default in simulation: kIsCFDinADCgate and kIsEventInTVDC float mAmpThresholdForReco = 24; // only channels with amplitude higher will participate in calibration and collision time short mTimeThresholdForReco = 1000; // only channels with time below will participate in calibration and collision time + int NchannelsLevel = 2; // trigger Nchannels + float InnerChargeLevel = 4; // InnerRingsChargeLevel + float OuterChargeLevel = 4; // OuterRingsChargeLevel + float ChargeLevel = 8; // ChargeLevel O2ParamDef(FV0DigParam, "FV0DigParam"); }; diff --git a/Detectors/FIT/FV0/simulation/src/Digitizer.cxx b/Detectors/FIT/FV0/simulation/src/Digitizer.cxx index 1c94b14f029cf..3237f9bab7879 100644 --- a/Detectors/FIT/FV0/simulation/src/Digitizer.cxx +++ b/Detectors/FIT/FV0/simulation/src/Digitizer.cxx @@ -38,8 +38,8 @@ void Digitizer::clear() void Digitizer::init() { 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 + mNBins = FV0DigParam::Instance().waveformNbins; // Will be computed using detector set-up from CDB + mBinSize = FV0DigParam::Instance().waveformBinWidth; // Will be set-up from CDB mNTimeBinsPerBC = std::lround(o2::constants::lhc::LHCBunchSpacingNS / mBinSize); // 1920 bins/BC for (Int_t detID = 0; detID < Constants::nFv0Channels; detID++) { @@ -98,6 +98,11 @@ void Digitizer::process(const std::vector& hits, for (auto ids : hitIdx) { const auto& hit = hits[ids]; Int_t detId = hit.GetDetectorID(); + + if (mDeadChannelMap && !mDeadChannelMap->isChannelAlive(detId)) { + continue; + } + Double_t hitEdep = hit.GetHitValue() * 1e3; // convert to MeV Float_t const hitTime = hit.GetTime() * 1e9; // convert to ns // TODO: check how big is inaccuracy if more than 1 'below-threshold' particles hit the same detector cell @@ -144,8 +149,8 @@ void Digitizer::process(const std::vector& hits, createPulse(mipFraction, hit.GetTrackID(), hitTime, hit.GetPos().R(), cachedIR, nCachedIR, detId); - } //while loop - } //hitloop + } // while loop + } // hitloop } void Digitizer::createPulse(float mipFraction, int parID, const double hitTime, const float hitR, @@ -195,7 +200,7 @@ void Digitizer::createPulse(float mipFraction, int parID, const double hitTime, } added[ir] = true; } - ///Add MC labels to BCs for those contributed to the PMT signal + /// Add MC labels to BCs for those contributed to the PMT signal for (int ir = 0; ir < nCachedIR; ir++) { if (added[ir]) { auto bcCache = getBCCache(cachedIR[ir]); @@ -233,6 +238,8 @@ void Digitizer::storeBC(const BCCache& bc, int8_t nTotFiredCells = 0; int8_t nTrgFiredCells = 0; // number of fired cells, that follow additional trigger conditions (time gate) int totalChargeAllRing = 0; + int totalChargeInnerRing = 0; + int totalChargeOuterRing = 0; int32_t avgTime = 0; double nSignalInner = 0; double nSignalOuter = 0; @@ -280,8 +287,10 @@ void Digitizer::storeBC(const BCCache& bc, avgTime += iCfdZero; if (iPmt < 24) { nSignalInner++; + totalChargeInnerRing += iTotalCharge; } else { nSignalOuter++; + totalChargeOuterRing += iTotalCharge; } } } @@ -295,13 +304,15 @@ void Digitizer::storeBC(const BCCache& bc, } else { avgTime = o2::fit::Triggers::DEFAULT_TIME; } - ///Triggers for FV0 - bool isA, isAIn, isAOut, isCen, isSCen; + /// Triggers for FV0 + bool isA, isNchannels, isAIn, isAOut, isTotalCharge; isA = nTrgFiredCells > 0; - isAIn = nSignalInner > 0; // ring 1,2 and 3 - isAOut = nSignalOuter > 0; // ring 4 and 5 - isCen = totalChargeAllRing > FV0DigParam::Instance().adcChargeCenThr; - isSCen = totalChargeAllRing > FV0DigParam::Instance().adcChargeSCenThr; + isNchannels = nTrgFiredCells > FV0DigParam::Instance().NchannelsLevel; + // isAIn = nSignalInner > FV0DigParam::Instance().NchannelsLevel; // ring 1,2 and 3 + isAIn = 0.125 * totalChargeInnerRing > 2 * FV0DigParam::Instance().InnerChargeLevel; // ring 1,2 and 3 + // isAOut = nSignalOuter > FV0DigParam::Instance().NchannelsLevel; // ring 4 and 5 + isAOut = 0.125 * totalChargeOuterRing > 2 * FV0DigParam::Instance().OuterChargeLevel; // ring 4 and 5 + isTotalCharge = 0.125 * totalChargeAllRing > 2 * FV0DigParam::Instance().ChargeLevel; Triggers triggers; const int unusedCharge = o2::fit::Triggers::DEFAULT_AMP; @@ -309,10 +320,10 @@ void Digitizer::storeBC(const BCCache& bc, const int unusedZero = o2::fit::Triggers::DEFAULT_ZERO; const bool unusedBitsInSim = false; // bits related to laser and data validity const bool bitDataIsValid = true; - triggers.setTriggers(isA, isAIn, isAOut, isCen, isSCen, nTrgFiredCells, (int8_t)unusedZero, + triggers.setTriggers(isA, isAIn, isAOut, isTotalCharge, isNchannels, nTrgFiredCells, (int8_t)unusedZero, (int32_t)(0.125 * totalChargeAllRing), (int32_t)unusedCharge, (int16_t)avgTime, (int16_t)unusedTime, unusedBitsInSim, unusedBitsInSim, bitDataIsValid); digitsBC.emplace_back(first, nTotFiredCells, bc, triggers, mEventId - 1); - digitsTrig.emplace_back(bc, isA, isAIn, isAOut, isCen, isSCen); + digitsTrig.emplace_back(bc, isA, isAIn, isAOut, isTotalCharge, isNchannels); for (auto const& lbl : bc.labels) { labels.addElement(nBC, lbl); } @@ -337,8 +348,8 @@ Int_t Digitizer::SimulateLightYield(Int_t pmt, Int_t nPhot) const //--------------------------------------------------------------------------- Float_t Digitizer::IntegrateCharge(const ChannelDigitF& pulse) const { - 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) + 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; } @@ -395,7 +406,7 @@ float Digitizer::getDistFromCellCenter(UInt_t cellId, double hitx, double hity) double a = -(y0 - pCell->y) / (x0 - pCell->x); double b = 1; double c = -(y0 - a * x0); - //Return the distance from hit to this line + // Return the distance from hit to this line return (a * hitx + b * hity + c) / TMath::Sqrt(a * a + b * b); } diff --git a/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyDecoderSpec.h b/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyDecoderSpec.h index 67b74f45e42bf..76f1aae5e728d 100644 --- a/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyDecoderSpec.h +++ b/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyDecoderSpec.h @@ -28,7 +28,7 @@ namespace fv0 class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity); + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -41,7 +41,7 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt); } // namespace fv0 } // namespace o2 diff --git a/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyEncoderSpec.h b/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyEncoderSpec.h index db4f154a302c7..0df9403a88a12 100644 --- a/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyEncoderSpec.h +++ b/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyEncoderSpec.h @@ -28,7 +28,7 @@ namespace fv0 class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR); + EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -42,7 +42,7 @@ class EntropyEncoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); } // namespace fv0 } // namespace o2 diff --git a/Detectors/FIT/FV0/workflow/include/FV0Workflow/RecoWorkflow.h b/Detectors/FIT/FV0/workflow/include/FV0Workflow/RecoWorkflow.h index 015870d9178e2..f035b2406e5ba 100644 --- a/Detectors/FIT/FV0/workflow/include/FV0Workflow/RecoWorkflow.h +++ b/Detectors/FIT/FV0/workflow/include/FV0Workflow/RecoWorkflow.h @@ -20,7 +20,7 @@ namespace o2 { namespace fv0 { -framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut); +framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut, bool useDeadChannelMap); } // 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 index d71e154280e3d..934ce4d2c4a66 100644 --- a/Detectors/FIT/FV0/workflow/include/FV0Workflow/ReconstructionSpec.h +++ b/Detectors/FIT/FV0/workflow/include/FV0Workflow/ReconstructionSpec.h @@ -34,7 +34,7 @@ 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(bool useMC, bool useDeadChannelMap, const std::string ccdbpath) : mUseMC(useMC), mUseDeadChannelMap(useDeadChannelMap), mCCDBpath(ccdbpath) {} ~ReconstructionDPL() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -44,6 +44,8 @@ class ReconstructionDPL : public Task private: bool mUseMC = false; bool mUpdateCCDB = true; + bool mUseDeadChannelMap = true; + bool mUpdateDeadChannelMap = true; const std::string mCCDBpath = o2::base::NameConf::getCCDBServer(); std::vector mRecPoints; std::vector mRecChData; @@ -53,7 +55,7 @@ class ReconstructionDPL : public Task }; /// create a processor spec -framework::DataProcessorSpec getReconstructionSpec(bool useMC = false, const std::string ccdbpath = "http://alice-ccdb.cern.ch"); +framework::DataProcessorSpec getReconstructionSpec(bool useMC = false, bool useDeadChannelMap = true, const std::string ccdbpath = "http://alice-ccdb.cern.ch"); } // namespace fv0 } // namespace o2 diff --git a/Detectors/FIT/FV0/workflow/src/EntropyDecoderSpec.cxx b/Detectors/FIT/FV0/workflow/src/EntropyDecoderSpec.cxx index 9310905ad41b9..6cf8043cf683f 100644 --- a/Detectors/FIT/FV0/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/FIT/FV0/workflow/src/EntropyDecoderSpec.cxx @@ -24,12 +24,12 @@ namespace o2 { namespace fv0 { - -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); mCTFCoder.setVerbosity(verbosity); + mCTFCoder.setSupportBCShifts(true); mCTFCoder.setDictBinding("ctfdict_FV0"); } @@ -73,7 +73,7 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"digits"}, "FV0", "DIGITSBC", 0, Lifetime::Timeframe}, @@ -82,17 +82,18 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) std::vector inputs; inputs.emplace_back("ctf_FV0", "FV0", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_FV0", "FV0", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FV0/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_FV0", "FV0", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FV0/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ "fv0-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace fv0 } // namespace o2 diff --git a/Detectors/FIT/FV0/workflow/src/EntropyEncoderSpec.cxx b/Detectors/FIT/FV0/workflow/src/EntropyEncoderSpec.cxx index a25c16a5d697c..2448af09fac4e 100644 --- a/Detectors/FIT/FV0/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/FIT/FV0/workflow/src/EntropyEncoderSpec.cxx @@ -25,8 +25,7 @@ namespace o2 { namespace fv0 { - -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR) { mTimer.Stop(); mTimer.Reset(); @@ -71,12 +70,15 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("digits", "FV0", "DIGITSBC", 0, Lifetime::Timeframe); inputs.emplace_back("channels", "FV0", "DIGITSCH", 0, Lifetime::Timeframe); - inputs.emplace_back("ctfdict", "FV0", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FV0/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "FV0", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FV0/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -85,13 +87,11 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR) inputs, Outputs{{"FV0", "CTFDATA", 0, Lifetime::Timeframe}, {{"ctfrep"}, "FV0", "CTFENCREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace fv0 } // namespace o2 diff --git a/Detectors/FIT/FV0/workflow/src/RecoWorkflow.cxx b/Detectors/FIT/FV0/workflow/src/RecoWorkflow.cxx index 6bfc5479303d1..a0ef71b75765a 100644 --- a/Detectors/FIT/FV0/workflow/src/RecoWorkflow.cxx +++ b/Detectors/FIT/FV0/workflow/src/RecoWorkflow.cxx @@ -22,14 +22,13 @@ namespace o2 namespace fv0 { -framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut) +framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut, bool useDeadChannelMap) { framework::WorkflowSpec specs; if (!disableRootInp) { specs.emplace_back(o2::fv0::getDigitReaderSpec(useMC)); } - - specs.emplace_back(o2::fv0::getReconstructionSpec(useMC)); + specs.emplace_back(o2::fv0::getReconstructionSpec(useMC, useDeadChannelMap)); if (!disableRootOut) { specs.emplace_back(o2::fv0::getRecPointWriterSpec(useMC)); } diff --git a/Detectors/FIT/FV0/workflow/src/ReconstructionSpec.cxx b/Detectors/FIT/FV0/workflow/src/ReconstructionSpec.cxx index 520ac4dbaa563..cdf297b334588 100644 --- a/Detectors/FIT/FV0/workflow/src/ReconstructionSpec.cxx +++ b/Detectors/FIT/FV0/workflow/src/ReconstructionSpec.cxx @@ -21,6 +21,7 @@ #include "DataFormatsFV0/ChannelData.h" #include "DataFormatsFV0/MCLabel.h" #include "DataFormatsFV0/FV0ChannelTimeCalibrationObject.h" +#include "DataFormatsFIT/DeadChannelMap.h" #include "Framework/CCDBParamSpec.h" using namespace o2::framework; @@ -41,6 +42,7 @@ void ReconstructionDPL::run(ProcessingContext& pc) { mTimer.Start(false); mRecPoints.clear(); + mRecChData.clear(); auto digits = pc.inputs().get>("digits"); auto digch = pc.inputs().get>("digch"); // RS: if we need to process MC truth, uncomment lines below @@ -53,18 +55,19 @@ void ReconstructionDPL::run(ProcessingContext& pc) auto caliboffsets = pc.inputs().get("fv0offsets"); mReco.SetChannelOffset(caliboffsets.get()); } + if (mUseDeadChannelMap && mUpdateDeadChannelMap) { + auto deadChannelMap = pc.inputs().get("deadChannelMap"); + mReco.SetDeadChannelMap(deadChannelMap.get()); + } int nDig = digits.size(); LOG(debug) << " 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(debug) << " ndig " << id << " bc " << digit.getBC() << " orbit " << digit.getOrbit(); auto channels = digit.getBunchChannelData(digch); - gsl::span out_ch(mRecChData); - out_ch = out_ch.subspan(digit.ref.getFirstEntry(), digit.ref.getEntries()); - mRecPoints.emplace_back(mReco.process(digit, channels, out_ch)); + mRecPoints.emplace_back(mReco.process(digit, channels, mRecChData)); } LOG(debug) << "FV0 reconstruction pushes " << mRecPoints.size() << " RecPoints"; @@ -80,6 +83,9 @@ void ReconstructionDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) mUpdateCCDB = false; return; } + if (matcher == ConcreteDataMatcher(o2::header::gDataOriginFV0, "DeadChannelMap", 0)) { + mUpdateDeadChannelMap = false; + } } void ReconstructionDPL::endOfStream(EndOfStreamContext& ec) @@ -88,7 +94,7 @@ void ReconstructionDPL::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getReconstructionSpec(bool useMC, const std::string ccdbpath) +DataProcessorSpec getReconstructionSpec(bool useMC, bool useDeadChannelMap, const std::string ccdbpath) { std::vector inputSpec; std::vector outputSpec; @@ -98,6 +104,10 @@ DataProcessorSpec getReconstructionSpec(bool useMC, const std::string ccdbpath) LOG(info) << "Currently Reconstruction does not consume and provide MC truth"; inputSpec.emplace_back("labels", o2::header::gDataOriginFV0, "DIGITSMCTR", 0, Lifetime::Timeframe); } + if (useDeadChannelMap) { + LOG(info) << "Dead channel map will be applied during reconstruction"; + inputSpec.emplace_back("deadChannelMap", o2::header::gDataOriginFV0, "DeadChannelMap", 0, Lifetime::Condition, ccdbParamSpec("FV0/Calib/DeadChannelMap")); + } inputSpec.emplace_back("fv0offsets", "FV0", "TimeOffset", 0, Lifetime::Condition, ccdbParamSpec("FV0/Calib/ChannelTimeOffset")); @@ -109,7 +119,7 @@ DataProcessorSpec getReconstructionSpec(bool useMC, const std::string ccdbpath) "fv0-reconstructor", inputSpec, outputSpec, - AlgorithmSpec{adaptFromTask(useMC, ccdbpath)}, + AlgorithmSpec{adaptFromTask(useMC, useDeadChannelMap, ccdbpath)}, Options{}}; } diff --git a/Detectors/FIT/FV0/workflow/src/entropy-encoder-workflow.cxx b/Detectors/FIT/FV0/workflow/src/entropy-encoder-workflow.cxx index 90f37996b55b7..932e0a37ee376 100644 --- a/Detectors/FIT/FV0/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/FIT/FV0/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "none", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -37,6 +38,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::fv0::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"))); + wf.emplace_back(o2::fv0::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/FIT/FV0/workflow/src/fv0-reco-workflow.cxx b/Detectors/FIT/FV0/workflow/src/fv0-reco-workflow.cxx index 16d1383c7e8c4..309560e2d6b36 100644 --- a/Detectors/FIT/FV0/workflow/src/fv0-reco-workflow.cxx +++ b/Detectors/FIT/FV0/workflow/src/fv0-reco-workflow.cxx @@ -39,6 +39,7 @@ void customize(std::vector& 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 readers"}}, {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}, + {"disable-dead-channel-map", o2::framework::VariantType::Bool, false, {"disable dead channel map"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); @@ -59,9 +60,10 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto useMC = !configcontext.options().get("disable-mc"); auto disableRootInp = configcontext.options().get("disable-root-input"); auto disableRootOut = configcontext.options().get("disable-root-output"); + bool useDeadChannelMap = !configcontext.options().get("disable-dead-channel-map"); LOG(info) << "WorkflowSpec getRecoWorkflow useMC " << useMC; - auto wf = o2::fv0::getRecoWorkflow(useMC, disableRootInp, disableRootOut); + auto wf = o2::fv0::getRecoWorkflow(useMC, disableRootInp, disableRootOut, useDeadChannelMap); // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit o2::raw::HBFUtilsInitializer hbfIni(configcontext, wf); diff --git a/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSConfigProcessorSpec.h b/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSConfigProcessorSpec.h index f3ed3229d9e55..18c0b593b0a02 100644 --- a/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSConfigProcessorSpec.h +++ b/Detectors/FIT/common/dcsmonitoring/include/FITDCSMonitoring/FITDCSConfigProcessorSpec.h @@ -47,7 +47,7 @@ class FITDCSConfigProcessor : public o2::framework::Task void init(o2::framework::InitContext& ic) final { initDCSConfigReader(); - mDCSConfigReader->setFileNameDChM(ic.options().get("filename-dchm")); + mDCSConfigReader->setFileNameDChM(ic.options().get("filename-dchm")); mDCSConfigReader->setValidDaysDChM(ic.options().get("valid-days-dchm")); mDCSConfigReader->setCcdbPathDChM(mDetectorName + "/Calib/DeadChannelMap"); mVerbose = ic.options().get("use-verbose-mode"); diff --git a/Detectors/FOCAL/base/include/FOCALBase/Geometry.h b/Detectors/FOCAL/base/include/FOCALBase/Geometry.h index 770c0aa3c1cf5..3414d84b5298f 100644 --- a/Detectors/FOCAL/base/include/FOCALBase/Geometry.h +++ b/Detectors/FOCAL/base/include/FOCALBase/Geometry.h @@ -59,6 +59,12 @@ class VirtualSegment class Geometry { public: + enum HCALDesgin { + Sandwich = 0, // Sandwich HCAL design + Spaghetti = 1, // Spaghetti design + Sheets = 2 // Sheets design + }; + Geometry() = default; Geometry(Geometry* geo); Geometry(const Geometry& geo) = default; @@ -134,6 +140,8 @@ class Geometry float getMiddleTowerOffset() const { return mGlobal_Middle_Tower_Offset; } bool getInsertFrontPadLayers() const { return mInsertFrontPadLayers; } bool getInsertHCalReadoutMaterial() const { return mInsertFrontHCalReadoutMaterial; } + float getHCALPitchSize() const { return mGlobal_HCAL_Pitch_Size; } + float getHCALBeamPipeHoleSize() const { return mGlobal_HCAL_BeamPipeHole_Size; } float getDetectorOpeningRight() const { return mGlobal_DetectorOpening_Right; } float getDetectorOpeningLeft() const { return mGlobal_DetectorOpening_Left; } @@ -158,7 +166,7 @@ class Geometry void setUpLayerSegmentMap(); void setUpTowerWaferSize(); - bool getUseHCALSandwich() { return mUseSandwichHCAL; } + HCALDesgin getHCALDesign() const { return mHCALDesign; } protected: std::vector mGeometryComposition; @@ -206,9 +214,11 @@ class Geometry std::string mGlobal_Gap_Material; // gap filling material NOTE: currently not used float mGlobal_HCAL_Tower_Size = 0.0; - int mGlobal_HCAL_Tower_NX = 0; // Number of HCAL towers on X - int mGlobal_HCAL_Tower_NY = 0; // Number of HCAL towers on Y - bool mUseSandwichHCAL = false; + int mGlobal_HCAL_Tower_NX = 0; // Number of HCAL towers on X + int mGlobal_HCAL_Tower_NY = 0; // Number of HCAL towers on Y + float mGlobal_HCAL_Pitch_Size = 0.0; // Distance between two fibers + float mGlobal_HCAL_BeamPipeHole_Size = 0.0; // beam pipe hole size in HCAL + HCALDesgin mHCALDesign = Sandwich; // HCAL design type float mGlobal_FOCAL_Z0 = 0.0; diff --git a/Detectors/FOCAL/base/src/Geometry.cxx b/Detectors/FOCAL/base/src/Geometry.cxx index db47816ba8537..2699ab5c7d602 100644 --- a/Detectors/FOCAL/base/src/Geometry.cxx +++ b/Detectors/FOCAL/base/src/Geometry.cxx @@ -366,6 +366,11 @@ void Geometry::setParameters(std::string geometryfile) LOG(debug) << "The size of the HCAL readout tower will be : " << mGlobal_HCAL_Tower_Size; } + if (command.find("HCAL_PITCH_SIZE") != std::string::npos) { + mGlobal_HCAL_Pitch_Size = std::stof(tokens[1]); + LOG(debug) << "The distance between fibers is : " << mGlobal_HCAL_Pitch_Size; + } + if (command.find("HCAL_TOWER_NX") != std::string::npos) { mGlobal_HCAL_Tower_NX = std::stoi(tokens[1]); LOG(debug) << "The number of the HCAL readout towers in X will be : " << mGlobal_HCAL_Tower_NX; @@ -376,6 +381,11 @@ void Geometry::setParameters(std::string geometryfile) LOG(debug) << "The number of the HCAL readout towers in Y will be : " << mGlobal_HCAL_Tower_NY; } + if (command.find("HCAL_BEAMPIPE") != std::string::npos) { + mGlobal_HCAL_BeamPipeHole_Size = std::stof(tokens[1]); + LOG(debug) << "The HCAL beam pipe openning : " << mGlobal_HCAL_BeamPipeHole_Size; + } + if (command.find("PIX_OffsetX") != std::string::npos) { mGlobal_PIX_OffsetX = std::stof(tokens[1]); LOG(debug) << "Pixel offset from the beam pipe will be: " << mGlobal_PIX_OffsetX; @@ -429,11 +439,6 @@ void Geometry::setParameters(std::string geometryfile) if (command.find("NUMBER_OF_HCAL_LAYERS") != std::string::npos) { mNHCalLayers = std::stoi(tokens[1]); LOG(debug) << "Number of HCAL layers " << mNHCalLayers; - if (mNHCalLayers == 1) { - mUseSandwichHCAL = false; - } else { - mUseSandwichHCAL = true; - } } if (command.find("NUMBER_OF_SEGMENTS") != std::string::npos) { @@ -640,6 +645,14 @@ void Geometry::setParameters(std::string geometryfile) mHCalLayerThickness = center_z; center_z = 0; + if (mNHCalLayers == 1 && hHCal > 2) { + mHCALDesign = Geometry::HCALDesgin::Sheets; + } else if (mNHCalLayers == 1 && hHCal == 2) { + mHCALDesign = Geometry::HCALDesgin::Spaghetti; + } else { + mHCALDesign = Geometry::HCALDesgin::Sandwich; + } + mFrontMatterLayerThickness = center_z; LOG(debug) << " end of SetParameters "; } @@ -702,27 +715,34 @@ std::tuple Geometry::getGeoTowerCenter(int tower, int se int ix = id % nCols; int iy = id / nRows; - if (mUseSandwichHCAL) { - float padSize = mVirtualSegmentComposition[segment].mPadSize; - double hCALsizeX = nCols * padSize; - double hCALsizeY = nRows * padSize; - x = ix * padSize + 0.5 * padSize - 0.5 * hCALsizeX; - y = iy * padSize + 0.5 * padSize - 0.5 * hCALsizeY; - } else { - nCols = std::floor(getFOCALSizeX() / getHCALTowerSize() + 0.001) + 1; - nRows = std::floor(getFOCALSizeY() / getHCALTowerSize() + 0.001); - ix = id % nCols; - iy = id / nRows; - double beamPipeRadius = 3.6; // in cm TODO: check if this is OK - double towerHalfDiag = std::sqrt(2) * 0.5 * getTowerSizeX(); // tower half diagonal - double minRadius = beamPipeRadius + towerHalfDiag; - - float towerSize = getHCALTowerSize() / 7; // To be set from outside (number of channels on x & y) - y = iy * towerSize + 0.5 * towerSize - 0.5 * towerSize * nRows; - x = ix * towerSize + 0.5 * towerSize - 0.5 * towerSize * nCols; - if (y < minRadius && y > -minRadius) { - x = int(x) <= 0 ? x - (minRadius - towerSize) : x + (minRadius - towerSize); + switch (mHCALDesign) { + case HCALDesgin::Sandwich: { + float padSize = mVirtualSegmentComposition[segment].mPadSize; + double hCALsizeX = nCols * padSize; + double hCALsizeY = nRows * padSize; + + x = ix * padSize + 0.5 * padSize - 0.5 * hCALsizeX; + y = iy * padSize + 0.5 * padSize - 0.5 * hCALsizeY; + break; } + case HCALDesgin::Spaghetti: { + float towerSize = getHCALTowerSize() / 7; // To be set from outside (number of channels on x & y) + y = iy * towerSize + 0.5 * towerSize - 0.5 * towerSize * nRows; + x = ix * towerSize + 0.5 * towerSize - 0.5 * towerSize * nCols; + break; + } + case HCALDesgin::Sheets: { + Composition comp1 = mHCalCompositionBase[0]; + Composition comp2 = mHCalCompositionBase[2]; + double hCALsizeX = comp1.sizeX() * 2; // Size of two sheet in X + double hCALsizeY = getHCALTowersInY() * (comp1.sizeY() + comp2.sizeY()) * 2; // To be set in a better way + + x = ix * hCALsizeX / getHCALTowersInX() + 0.5 * hCALsizeX / getHCALTowersInX() - 0.5 * hCALsizeX; + y = iy * hCALsizeY / getHCALTowersInY() + 0.5 * hCALsizeY / getHCALTowersInY() - 0.5 * hCALsizeY; + break; + } + default: + break; } } @@ -1118,12 +1138,41 @@ std::tuple Geometry::getVirtualInfo(double x, double y x = x < 0 ? x - 0.001 : x + 0.001; y = y < 0 ? y - 0.001 : y + 0.001; } - if (!mUseSandwichHCAL) { - row = (int)((y + hCALsizeY / 2) / (towerSize / 7)); - col = (int)((x + hCALsizeX / 2) / (towerSize / 7)); - } else { - row = (int)((y + hCALsizeY / 2) / (towerSize)); - col = (int)((x + hCALsizeX / 2) / (towerSize)); + + switch (mHCALDesign) { + case HCALDesgin::Sandwich: { + row = (int)((y + hCALsizeY / 2) / (towerSize)); + col = (int)((x + hCALsizeX / 2) / (towerSize)); + break; + } + case HCALDesgin::Spaghetti: { + row = (int)((y + hCALsizeY / 2) / (towerSize / 7)); + col = (int)((x + hCALsizeX / 2) / (towerSize / 7)); + break; + } + case HCALDesgin::Sheets: { + Composition comp1 = mHCalCompositionBase[0]; + Composition comp2 = mHCalCompositionBase[2]; + double hCALsizeX = comp1.sizeX() * 2; // Size of two sheet in X + double hCALsizeY = getHCALTowersInY() * (comp1.sizeY() + comp2.sizeY()) * 2; // To be set in a better way + + if (y < getHCALBeamPipeHoleSize() / 2 && y > -getHCALBeamPipeHoleSize() / 2) { + if (x < 0) { + x += 1.0; // remove the offset around the beam pipe + } else { + x -= 1.0; // remove the offset around the beam pipe + } + } + + row = (int)((y + hCALsizeY / 2) / (hCALsizeY / getHCALTowersInY())); + if (x > 0) { + x = x - 0.15 - 0.06; + } + col = (int)((x - 0.15 + hCALsizeX / 2) / ((hCALsizeX - 0.15 * 2 - 0.06 * 2) / getHCALTowersInX())); + break; + } + default: + break; } } else { row = (int)((y + getFOCALSizeY() / 2) / mVirtualSegmentComposition[segment].mPadSize); @@ -1150,12 +1199,29 @@ std::tuple Geometry::getXYZFromColRowSeg(int col, double hCALsizeX = getHCALTowersInX() * towerSize; double hCALsizeY = getHCALTowersInY() * towerSize; - if (!mUseSandwichHCAL) { - y = -1 * hCALsizeY / 2 + ((float)row + 0.5) * (towerSize / 7); - x = -1 * hCALsizeX / 2 + ((float)col + 0.5) * (towerSize / 7); - } else { - y = -1 * hCALsizeY / 2 + ((float)row + 0.5) * (towerSize); - x = -1 * hCALsizeX / 2 + ((float)col + 0.5) * (towerSize); + switch (mHCALDesign) { + case HCALDesgin::Sandwich: { + y = -1 * hCALsizeY / 2 + ((float)row + 0.5) * (towerSize); + x = -1 * hCALsizeX / 2 + ((float)col + 0.5) * (towerSize); + break; + } + case HCALDesgin::Spaghetti: { + y = -1 * hCALsizeY / 2 + ((float)row + 0.5) * (towerSize / 7); + x = -1 * hCALsizeX / 2 + ((float)col + 0.5) * (towerSize / 7); + break; + } + case HCALDesgin::Sheets: { + Composition comp1 = mHCalCompositionBase[0]; + Composition comp2 = mHCalCompositionBase[2]; + double hCALsizeX = comp1.sizeX() * 2; // Size of two sheet in X + double hCALsizeY = getHCALTowersInY() * (comp1.sizeY() + comp2.sizeY()) * 2; // To be set in a better way + + y = -1 * hCALsizeY / 2 + ((float)row + 0.5) * (hCALsizeY / getHCALTowersInY()); + x = -1 * hCALsizeX / 2 + ((float)col + 0.5) * (hCALsizeX / getHCALTowersInX()); + break; + } + default: + break; } } else { y = -1 * getFOCALSizeY() / 2 + ((float)row + 0.5) * mVirtualSegmentComposition[segment].mPadSize; @@ -1191,12 +1257,24 @@ std::tuple Geometry::getVirtualNColRow(int segment) const nCol = (int)(getFOCALSizeX() / mVirtualSegmentComposition[segment].mPadSize + 0.001); nRow = (int)(getFOCALSizeY() / mVirtualSegmentComposition[segment].mPadSize + 0.001); if (getVirtualIsHCal(segment)) { - if (!mUseSandwichHCAL) { - nCol = getHCALTowersInX() * 7; // To be set from outside (number of channels in each tower on x) - nRow = getHCALTowersInY() * 7; // To be set from outside (number of channels in each tower on y) - } else { - nCol = getHCALTowersInX(); - nRow = getHCALTowersInY(); + switch (mHCALDesign) { + case HCALDesgin::Sandwich: { + nCol = getHCALTowersInX(); + nRow = getHCALTowersInY(); + break; + } + case HCALDesgin::Spaghetti: { + nCol = getHCALTowersInX() * 7; // To be set from outside (number of channels in each tower on x) + nRow = getHCALTowersInY() * 7; // To be set from outside (number of channels in each tower on y) + break; + } + case HCALDesgin::Sheets: { + nCol = getHCALTowersInX(); + nRow = getHCALTowersInY(); + break; + } + default: + break; } } return {true, nCol, nRow}; diff --git a/Detectors/FOCAL/simulation/data/simcuts.dat b/Detectors/FOCAL/simulation/data/simcuts.dat index 744f67c3c81f4..870e38182f01c 100644 --- a/Detectors/FOCAL/simulation/data/simcuts.dat +++ b/Detectors/FOCAL/simulation/data/simcuts.dat @@ -14,3 +14,5 @@ FOC 3 1.e-4 1.e-4 1.e-4 1.e-4 1.e-4 1.e-4 1.e-4 1.e-4 1.e-4 -1. - FOC 6 5.e-5 1.e-4 1.e-4 1.e-4 1.e-4 1.e-4 1.e-4 1.e-4 1.e-4 -1. -1 -1 -1 -1 1 -1 3 -1 -1 -1 -1 -1 * Aluminium FOC 11 5.e-5 1.e-4 1.e-4 1.e-4 1.e-4 1.e-4 1.e-4 1.e-4 1.e-4 -1. -1 -1 -1 -1 1 -1 3 -1 -1 -1 -1 -1 +* Air +FOC 13 1.e-4 1.e-4 1.e-4 1.e-4 1.e-4 1.e-4 1.e-4 1.e-4 1.e-4 -1. -1 -1 -1 -1 1 -1 3 -1 -1 -1 -1 -1 diff --git a/Detectors/FOCAL/simulation/geometryFiles/geometry_Sheets.txt b/Detectors/FOCAL/simulation/geometryFiles/geometry_Sheets.txt new file mode 100644 index 0000000000000..358fcef2cd29d --- /dev/null +++ b/Detectors/FOCAL/simulation/geometryFiles/geometry_Sheets.txt @@ -0,0 +1,86 @@ +# Volume Name Material C-X C-Y X Y Z + COMPOSITION_PAD_S0 Alloy 0 0 9. 8. 0.35 + COMPOSITION_PAD_S1 G10 0 0 9. 8. 0.08 + COMPOSITION_PAD_S2 SiPad 0 0 9. 8. 0.03 + COMPOSITION_PAD_S3 G10 0 0 9. 8. 0.08 + COMPOSITION_PAD_S4 Cu 0 0 9. 8. 0.014 + COMPOSITION_PAD_S5 Air 0 0 9. 8. 0.296 + # Replica of above pad layers to 50 layers + COMMAND_NUMBER_OF_PAD_LAYERS 18 +# HCAL layers +# Volume Name Material C-X C-Y X Y Z + COMPOSITION_HCAL_S0 CuHCAL 0 0 49.81 0.20 110 + COMPOSITION_HCAL_S1 Scint 0 0 0.1 0.1 110 + COMPOSITION_HCAL_S2 CuHCAL 0 0 49.81 0.15 110 + COMMAND_NUMBER_OF_HCAL_LAYERS 1 + COMMAND_NUMBER_OF_SEGMENTS 21 +# Strip sectors +# Volume Name Material C-X C-Y X Y Z + COMPOSITION_PIX_S0 Alloy 0 0 3.0 2.74 0.35 + COMPOSITION_PIX_S1 G10 0 0 3.0 2.74 0.1 + COMPOSITION_PIX_S2 Si 0 0 3.0 2.74 0.047 + COMPOSITION_PIX_S3 SiPix 0 0 3.0 2.74 0.003 + COMPOSITION_PIX_S4 G10 0 0 3.0 2.74 0.1 + COMPOSITION_PIX_S5 Cu 0 0 3.0 2.74 0.001 + COMPOSITION_PIX_S6 Air 0 0 3.0 2.74 0.249 +COMMAND_INSERT_PIX_AT_L4 +COMMAND_INSERT_PIX_AT_L9 +# COMMAND_INSERT_STR_AT_L4 +# COMMAND_INSERT_STR_AT_L6 +# COMMAND_INSERT_STR_AT_L8 +#Front Matter definition + COMPOSITION_FM_S0 G10 0 0 5. 5. 0.01 + COMPOSITION_FM_S1 SiStripX 0 0 5. 5. 0.05 + COMPOSITION_FM_S2 G10 0 0 5. 5. 0.05 + COMPOSITION_FM_S3 Air 0 0 5. 5. 0.01 + COMPOSITION_FM_S4 G10 0 0 5. 5. 0.01 + COMPOSITION_FM_S5 SiStripY 0 0 5. 5. 0.05 + COMPOSITION_FM_S6 G10 0 0 5. 5. 0.05 +# PIXEL readout + GLOBAL_PIX_NX 15 + GLOBAL_PIX_NY 3 + GLOBAL_PIX_OffsetX 1.2 + GLOBAL_PIX_OffsetY 0.09 + GLOBAL_PIX_SKIN 0.004 +# pxel size in cm + COMMAND_PIXEL_READOUT_ON 0.005 +# Pad information + GLOBAL_PAD_SIZE_X_Y 1 + GLOBAL_PAD_NX_NY 8 + GLOBAL_PAD_NX 9 + GLOBAL_PAD_NY 8 + GLOBAL_PAD_PPTOL 0. + GLOBAL_PAD_SKIN 0.2 +# Global information (TOL:1cm of T-T space filled with "AIR") + GLOBAL_PAD_SUPERMODULE_X 5 + GLOBAL_PAD_SUPERMODULE_Y 1 + GLOBAL_SUPERMODULE_TOLX 0. Air + GLOBAL_SUPERMODULE_TOLY 0. Air + GLOBAL_TOWER_TOL 0. Air + GLOBAL_TOWER_TOLX 0.02 Air + GLOBAL_TOWER_TOLY 0.8 Al + GLOBAL_FOCAL_Z 764.47 + GLOBAL_Tower_NX 2 + GLOBAL_Tower_NY 11 + GLOBAL_MIDDLE_TOWER_OFFSET 5 + GLOBAL_NSTRIPS 128 + GLOBAL_STRIPSIZE_LONG 9.0 + GLOBAL_STRIPSIZE_WIDTH 0.07 + GLOBAL_HCAL_PITCH_SIZE 0.4 + GLOBAL_HCAL_TOWER_NY 72 + GLOBAL_HCAL_TOWER_NX 62 + GLOBAL_HCAL_BEAMPIPE 8.4 +# COMMAND_INSERT_FRONT_PAD_LAYERS +# COMMAND_INSERT_HCAL_READOUT +# New VIRTUAL settings + VIRTUAL_N_SEGMENTS 7 + # N Start End PadSize RelThickness IsPixel PixelTreshold [eV] + # Layer Layer + VIRTUAL_SEGMENT_LAYOUT_N0 0 3 1.0 1.0 0 300000 + VIRTUAL_SEGMENT_LAYOUT_N1 4 4 0.05 1.0 1 4000 + VIRTUAL_SEGMENT_LAYOUT_N2 5 8 1.0 1.0 0 300000 + VIRTUAL_SEGMENT_LAYOUT_N3 9 9 0.05 1.0 1 4000 + VIRTUAL_SEGMENT_LAYOUT_N4 10 14 1.0 1.0 0 375000 + VIRTUAL_SEGMENT_LAYOUT_N5 15 19 1.0 1.0 0 375000 + VIRTUAL_SEGMENT_LAYOUT_N6 20 20 0.4 1.0 2 5000 +#EOF diff --git a/Detectors/FOCAL/simulation/include/FOCALSimulation/Detector.h b/Detectors/FOCAL/simulation/include/FOCALSimulation/Detector.h index e7b887d206831..5f6bed3a037b0 100644 --- a/Detectors/FOCAL/simulation/include/FOCALSimulation/Detector.h +++ b/Detectors/FOCAL/simulation/include/FOCALSimulation/Detector.h @@ -17,6 +17,7 @@ #include "DetectorsBase/Detector.h" #include "FOCALBase/Hit.h" #include "FOCALBase/Geometry.h" +#include "TGeoManager.h" class FairVolume; @@ -157,6 +158,17 @@ class Detector : public o2::base::DetImpl virtual void CreateHCALSpaghetti(); virtual void CreateHCALSandwich(); + virtual void CreateHCALSheets(); + + TGeoVolumeAssembly* CreatePitchAssembly(double Lx = 498.1, + double Ly1 = 2.0, + double Ly2 = 1.5, + double Lz = 1100.0, + double hole_diameter = 1.1, + double hole_spacing = 4.0, + int nholes = 124, + double fiber_radius = 0.5, + std::string suffix = ""); /// \brief Generate ECAL geometry void CreateECALGeometry(); diff --git a/Detectors/FOCAL/simulation/src/Detector.cxx b/Detectors/FOCAL/simulation/src/Detector.cxx index 164b531e60918..464e57c07e676 100644 --- a/Detectors/FOCAL/simulation/src/Detector.cxx +++ b/Detectors/FOCAL/simulation/src/Detector.cxx @@ -480,11 +480,23 @@ void Detector::ConstructGeometry() CreateECALGeometry(); // HCAL part - if (mGeometry->getUseHCALSandwich()) { - CreateHCALSandwich(); - } else { - CreateHCALSpaghetti(); + switch (mGeometry->getHCALDesign()) { + case Geometry::HCALDesgin::Sandwich: + CreateHCALSandwich(); + break; + + case Geometry::HCALDesgin::Spaghetti: + CreateHCALSpaghetti(); + break; + + case Geometry::HCALDesgin::Sheets: + CreateHCALSheets(); + break; + + default: + break; } + // const float z0 = 1312.5; // center of barrel mother volume TVirtualMC::GetMC()->Gspos("FOCAL", 1, "barrel", 0, 30., mGeometry->getFOCALZ0() - (mGeometry->getInsertFrontPadLayers() ? 2.0 : 0.0) + (mGeometry->getInsertHCalReadoutMaterial() ? 1.5 : 0.0), 0, "ONLY"); } @@ -681,6 +693,219 @@ void Detector::CreateHCALSpaghetti() TVirtualMC::GetMC()->Gspos("HCAL", 1, "FOCAL", 0, 0, mGeometry->getHCALCenterZ() - mGeometry->getFOCALSizeZ() / 2 + 0.01 + (mGeometry->getInsertFrontPadLayers() ? 2.0 : 0.0) - (mGeometry->getInsertHCalReadoutMaterial() ? 1.5 : 0.0), 0, "ONLY"); } +//_____________________________________________________________________________ +TGeoVolumeAssembly* Detector::CreatePitchAssembly(double Lx, + double Ly1, + double Ly2, + double Lz, + double hole_diameter, + double hole_spacing, + int nholes, + double fiber_radius, + std::string suffix) +{ + + // Z-alignment doesn't change + double zpos = 0; + + TGeoMedium* copper = gGeoManager->GetMedium(getMediumID(ID_COPPER)); + TGeoMedium* scint = gGeoManager->GetMedium(getMediumID(ID_SC)); + + TGeoVolumeAssembly* pitchAssembly = new TGeoVolumeAssembly("pitchAssembly"); + + // Hardcoded values for hole placement, to be set from outside + float holeStart = 0.15; // cm + float holeEnd = 0.35; // cm + + TGeoVolumeAssembly* volLowerSheetwHoles = new TGeoVolumeAssembly(Form("volLowerSheetwHoles_%s", suffix.c_str())); + TGeoVolume* cuSheet = gGeoManager->MakeBox("cuSheet", copper, Lx / 2, (Ly1 - fiber_radius * 2) / 2, Lz / 2); + cuSheet->SetLineColor(kOrange + 2); + mSensitive.push_back(cuSheet->GetName()); + TGeoVolume* boxbegin = gGeoManager->MakeBox("BoxBegin", copper, holeStart / 2, fiber_radius, Lz / 2); + boxbegin->SetLineColor(kOrange + 2); + mSensitive.push_back(boxbegin->GetName()); + TGeoVolume* boxMiddle = gGeoManager->MakeBox("BoxMiddle", copper, (hole_spacing - hole_diameter) / 2, fiber_radius, Lz / 2); + boxMiddle->SetLineColor(kOrange + 2); + mSensitive.push_back(boxMiddle->GetName()); + TGeoVolume* boxEnd = gGeoManager->MakeBox("BoxEnd", copper, holeEnd / 2, fiber_radius, Lz / 2); + boxEnd->SetLineColor(kOrange + 2); + mSensitive.push_back(boxEnd->GetName()); + + double yPlacement = Ly1 / 2 - fiber_radius; + + // ----------------- + // Layer 1: Lower sheet with holes (y = 0) + // ----------------- + + volLowerSheetwHoles->AddNode(cuSheet, 0, new TGeoTranslation(0, -Ly1 / 2 + (Ly1 - fiber_radius * 2) / 2, zpos)); + + // Add holes starting at x = 1.5 mm + float start_x = -Lx / 2 + holeStart; + + for (int ihole = 0; ihole < nholes; ++ihole) { + float holePlacement = start_x + ihole * hole_spacing + hole_diameter / 2; + if (ihole == 0) { + volLowerSheetwHoles->AddNode(boxbegin, ihole, new TGeoTranslation(holePlacement - holeStart / 2 - hole_diameter / 2, yPlacement, zpos)); + volLowerSheetwHoles->AddNode(boxMiddle, ihole, new TGeoTranslation(holePlacement + hole_diameter / 2 + (hole_spacing - hole_diameter) / 2, yPlacement, zpos)); + } else if (ihole == nholes - 1) { + if ((holePlacement + hole_diameter / 2 + holeStart) < Lx / 2 - 0.005) { + volLowerSheetwHoles->AddNode(boxEnd, ihole, new TGeoTranslation(holePlacement + hole_diameter / 2 + holeEnd / 2, yPlacement, zpos)); + } else { + volLowerSheetwHoles->AddNode(boxbegin, ihole, new TGeoTranslation(holePlacement + hole_diameter / 2 + holeStart / 2, yPlacement, zpos)); + } + } else { + volLowerSheetwHoles->AddNode(boxMiddle, ihole, new TGeoTranslation(holePlacement + hole_diameter / 2 + (hole_spacing - hole_diameter) / 2, yPlacement, zpos)); + } + } + + pitchAssembly->AddNode(volLowerSheetwHoles, 0, new TGeoTranslation(0, Ly1 / 2, zpos)); // Add Ly1 / 2 so the lower edge of the sheets start y=0 + + // ----------------- + // Layer 2: Full copper sheet + // ----------------- + TGeoVolume* fullSheet1 = gGeoManager->MakeBox("FullSheet1", copper, Lx / 2, Ly2 / 2, Lz / 2); + fullSheet1->SetLineColor(kOrange + 2); + mSensitive.push_back(fullSheet1->GetName()); + pitchAssembly->AddNode(fullSheet1, 0, new TGeoTranslation(0, Ly1 / 2 + Ly2 / 2 + Ly1 / 2, zpos)); // Add Ly1 / 2 so the lower edge of the sheets start y=0 + + // ----------------- + // Layer 3: Upper sheet with holes (shifted) + // ----------------- + + TGeoVolumeAssembly* volUpperSheetwHoles = new TGeoVolumeAssembly(Form("volUpperSheetwHoles_%s", suffix.c_str())); + + volUpperSheetwHoles->AddNode(cuSheet, 0, new TGeoTranslation(0, -Ly1 / 2 + (Ly1 - fiber_radius * 2) / 2, zpos)); + + // Add holes starting at x = 3.5 mm + float start_x2 = -Lx / 2 + holeEnd; + + for (int ihole = 0; ihole < nholes; ++ihole) { + float holePlacement = start_x2 + ihole * hole_spacing + hole_diameter / 2; + if (ihole == 0) { + volUpperSheetwHoles->AddNode(boxEnd, ihole, new TGeoTranslation(holePlacement - hole_diameter / 2 - holeEnd / 2, yPlacement, zpos)); + volUpperSheetwHoles->AddNode(boxMiddle, ihole, new TGeoTranslation(holePlacement + hole_diameter / 2 + (hole_spacing - hole_diameter) / 2, yPlacement, zpos)); + } else if (ihole == nholes - 1) { + volUpperSheetwHoles->AddNode(boxbegin, ihole, new TGeoTranslation(holePlacement + holeStart / 2 + hole_diameter / 2, yPlacement, zpos)); + } else { + if ((holePlacement + hole_spacing + hole_diameter / 2) < Lx / 2 - 0.005) { + volUpperSheetwHoles->AddNode(boxMiddle, ihole, new TGeoTranslation(holePlacement + hole_diameter / 2 + (hole_spacing - hole_diameter) / 2, yPlacement, zpos)); + } else { + volUpperSheetwHoles->AddNode(boxEnd, ihole, new TGeoTranslation(holePlacement + hole_diameter / 2 + holeEnd / 2, yPlacement, zpos)); + break; + } + } + } + + pitchAssembly->AddNode(volUpperSheetwHoles, 0, new TGeoTranslation(0, Ly1 / 2 + Ly2 + Ly1 / 2 + Ly1 / 2, zpos)); // Add Ly1 / 2 so the lower edge of the sheets start y=0 + + // ----------------- + // Layer 4: Full copper sheet + // ----------------- + pitchAssembly->AddNode(fullSheet1, 1, new TGeoTranslation(0, Ly1 / 2 + Ly2 + Ly1 + Ly2 / 2 + Ly1 / 2, zpos)); // Add Ly1 / 2 so the lower edge of the sheets start y=0 + + // ----------------- + // Scintillator Fibers + // ----------------- + // Lower set of fibers + TGeoVolume* fiber = gGeoManager->MakeTube("Fiber", scint, 0, fiber_radius, Lz / 2); + fiber->SetLineColor(kBlue); + mSensitive.push_back(fiber->GetName()); + for (int i = 0; i < nholes; ++i) { + float x_fiber = start_x + i * hole_spacing + hole_diameter / 2; + pitchAssembly->AddNode(fiber, i, new TGeoTranslation(x_fiber, Ly1 / 2 - fiber_radius + Ly1 / 2, zpos)); + } + + // Upper set of fibers + for (int i = 0; i < nholes; ++i) { + float x_fiber = start_x2 + i * hole_spacing + hole_diameter / 2; + if (x_fiber > Lx / 2 - 0.05) { + break; + } + pitchAssembly->AddNode(fiber, i + nholes, new TGeoTranslation(x_fiber, Ly1 / 2 + Ly2 + Ly1 / 2 + Ly1 / 2 - fiber_radius + Ly1 / 2, zpos)); + } + + return pitchAssembly; +} + +//_____________________________________________________________________________ +void Detector::CreateHCALSheets() +{ + TGeoVolumeAssembly* volHCAL = new TGeoVolumeAssembly("HCAL"); + + // Dimensions + double Lx = 49.81; // cm + double Ly1 = 0.20; // cm (sheets with holes) + double Ly2 = 0.15; // cm (full sheets) + double Lz = 110.0; // cm + + double fiber_radius = 0.05; + + // HCal materials + int icomp = 0; + for (auto& comp : mGeoCompositions) { + Lz = comp->sizeZ(); + + if (comp->material() == "Scint") { + fiber_radius = comp->sizeX() / 2; + } + if (comp->material() == "CuHCAL" && icomp == 0) { + Lx = comp->sizeX(); + Ly1 = comp->sizeY(); + } + if (comp->material() == "CuHCAL" && icomp == 2) { + Ly2 = comp->sizeY(); + } + icomp++; + } + + double hole_diameter = fiber_radius * 2 + 0.01; // hole radius + double hole_spacing = mGeometry->getHCALPitchSize(); + int nholes = (int)(Lx / hole_spacing); // Number of holes in one HCAL sheet + + double beamPipeHole = mGeometry->getHCALBeamPipeHoleSize(); // cm The size of the beam pipe opening + int nBeamPipeHoles = (int)((Lx - beamPipeHole / 2) / hole_spacing); // Number of beam pipe holes + + // Compute module height (two sheets with holes + two full sheets) + float pitch_height = Ly1 + Ly2 + Ly1 + Ly2; + + int totalNumberOfPitches = mGeometry->getHCALTowersInY() * 2; // Number of pitches in the whole HCAL + int numberOfPitchesBeamPipe = (int)((beamPipeHole + 0.001) / pitch_height); // Number of pitches in the beam pipe region + int numberofPitchesOnYaxis = (totalNumberOfPitches - numberOfPitchesBeamPipe); // Number of pitches in the HCAL ouside the beam pipe region + + TGeoVolumeAssembly* pitchAssembly = CreatePitchAssembly(Lx, Ly1, Ly2, Lz, hole_diameter, hole_spacing, nholes, fiber_radius, "Main"); + pitchAssembly->SetVisibility(true); + TGeoVolumeAssembly* beamPipeAssembly = CreatePitchAssembly(Lx - beamPipeHole / 2, Ly1, Ly2, Lz, hole_diameter, hole_spacing, nBeamPipeHoles, fiber_radius, "BeamPipe"); + beamPipeAssembly->SetVisibility(true); + + TGeoVolumeAssembly* HalfHCAL = new TGeoVolumeAssembly("HalfHCAL"); + + for (int iPitch = 0; iPitch < numberofPitchesOnYaxis; iPitch++) { + float placement = iPitch * pitch_height - pitch_height * (totalNumberOfPitches) / 2.0; + if (placement < -beamPipeHole / 2.0) { + HalfHCAL->AddNode(pitchAssembly, iPitch, new TGeoTranslation(0, placement, 0.)); + } else { + placement += beamPipeHole; + HalfHCAL->AddNode(pitchAssembly, iPitch, new TGeoTranslation(0, placement, 0.)); + } + } + + for (int iPitch = 0; iPitch < numberOfPitchesBeamPipe; iPitch++) { + float placement = iPitch * pitch_height - beamPipeHole / 2.0; + HalfHCAL->AddNode(beamPipeAssembly, iPitch, new TGeoTranslation(-beamPipeHole / 4, placement, 0.)); + } + + HalfHCAL->SetVisibility(true); + HalfHCAL->SetVisDaughters(true); + + volHCAL->AddNode(HalfHCAL, 0, new TGeoTranslation(-Lx / 2, 0, 0.)); + TGeoRotation* rotFlipZ = new TGeoRotation(); + rotFlipZ->RotateY(180); // Flip around Y to reverse Z + TGeoCombiTrans* combHalf = new TGeoCombiTrans(Lx / 2, 0., 0., rotFlipZ); + volHCAL->AddNode(HalfHCAL, 1, combHalf); + + gMC->Gspos("HCAL", 1, "FOCAL", 0, 0, mGeometry->getHCALCenterZ() - mGeometry->getFOCALSizeZ() / 2 + 0.01 + (mGeometry->getInsertFrontPadLayers() ? 2.0 : 0.0) - (mGeometry->getInsertHCalReadoutMaterial() ? 1.5 : 0.0), 0, "ONLY"); +} + //_____________________________________________________________________________ void Detector::CreateHCALSandwich() { @@ -819,7 +1044,7 @@ void Detector::CreateECALGeometry() double pars[4]; // this is EMSC Assembly pars[0] = geom->getTowerSizeX() / 2. + geom->getTowerGapSizeX() / 2.; pars[1] = geom->getTowerSizeY() / 2. + geom->getTowerGapSizeY() / 2.; - // pars[2] = fGeom->GetFOCALSizeZ() / 2; + // pars[2] = mGeometry->GetFOCALSizeZ() / 2; pars[2] = geom->getECALSizeZ() / 2; pars[3] = 0; // this shifts all the pixel layers to the center near the beampipe diff --git a/Detectors/Filtering/src/FilteringSpec.cxx b/Detectors/Filtering/src/FilteringSpec.cxx index 847fa2cf7e1e5..ea82b1456d955 100644 --- a/Detectors/Filtering/src/FilteringSpec.cxx +++ b/Detectors/Filtering/src/FilteringSpec.cxx @@ -38,7 +38,6 @@ #include "Framework/InputRecordWalker.h" #include "Framework/Logger.h" #include "Framework/TableBuilder.h" -#include "Framework/TableTreeHelpers.h" #include "Framework/CCDBParamSpec.h" #include "FDDBase/Constants.h" #include "FT0Base/Geometry.h" @@ -47,7 +46,7 @@ #include "ReconstructionDataFormats/Cascade.h" #include "MCHTracking/TrackExtrap.h" #include "MCHTracking/TrackParam.h" -#include "ITSMFTBase/DPLAlpideParam.h" +#include "DataFormatsITSMFT/DPLAlpideParam.h" #include "DetectorsVertexing/PVertexerParams.h" #include "ReconstructionDataFormats/GlobalTrackID.h" #include "ReconstructionDataFormats/Track.h" diff --git a/Detectors/Filtering/src/filtering-workflow.cxx b/Detectors/Filtering/src/filtering-workflow.cxx index 8e36cfc36b197..faf5463281ed8 100644 --- a/Detectors/Filtering/src/filtering-workflow.cxx +++ b/Detectors/Filtering/src/filtering-workflow.cxx @@ -17,6 +17,7 @@ #include "DetectorsCommonDataFormats/DetID.h" #include "DetectorsRaw/HBFUtilsInitializer.h" #include "Framework/CallbacksPolicy.h" +#include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" using namespace o2::framework; using GID = o2::dataformats::GlobalTrackID; @@ -36,6 +37,7 @@ void customize(std::vector& workflowOptions) {"disable-secondary-vertices", o2::framework::VariantType::Bool, false, {"disable filling secondary vertices"}}, {"data-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of sources to use"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + o2::itsmft::DPLAlpideParamInitializer::addConfigOption(options); o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } diff --git a/Detectors/GRP/calibration/src/GRPDCSDPsProcessor.cxx b/Detectors/GRP/calibration/src/GRPDCSDPsProcessor.cxx index c8fa7c2bff38b..aec4241f4f8db 100644 --- a/Detectors/GRP/calibration/src/GRPDCSDPsProcessor.cxx +++ b/Detectors/GRP/calibration/src/GRPDCSDPsProcessor.cxx @@ -277,13 +277,13 @@ bool GRPDCSDPsProcessor::processLHCIFDPs(const DPCOM& dpcom) } for (int ibeam = 0; ibeam < GRPLHCInfo::BeamAliases::NBeamAliases; ++ibeam) { - if (aliasStr.find(static_cast(GRPLHCInfo::beamAliases[ibeam])) != string::npos) { + if (aliasStr.find(static_cast(GRPLHCInfo::beamAliases[ibeam])) != std::string::npos) { updateVector(dpid, mLHCInfo.mIntensityBeam[ibeam], aliasStr, dpcomdata.get_epoch_time(), val); return true; } } - if (aliasStr.find("BPTX") != string::npos) { + if (aliasStr.find("BPTX") != std::string::npos) { if (aliasStr == static_cast(GRPLHCInfo::bptxAliases[GRPLHCInfo::BPTXAliases::BPTX_deltaT_B1_B2])) { updateVector(dpid, mLHCInfo.mBPTXdeltaT, aliasStr, dpcomdata.get_epoch_time(), val); return true; @@ -318,7 +318,7 @@ bool GRPDCSDPsProcessor::processLHCIFDPs(const DPCOM& dpcom) } for (int ibkg = 0; ibkg < 3; ++ibkg) { - if (aliasStr.find(static_cast(GRPLHCInfo::bkgAliases[ibkg])) != string::npos) { + if (aliasStr.find(static_cast(GRPLHCInfo::bkgAliases[ibkg])) != std::string::npos) { updateVector(dpid, mLHCInfo.mBackground[ibkg], aliasStr, dpcomdata.get_epoch_time(), val); return true; } diff --git a/Detectors/GRP/workflows/src/create-grp-ecs.cxx b/Detectors/GRP/workflows/src/create-grp-ecs.cxx index 873133e0dd46b..d9a73f0737799 100644 --- a/Detectors/GRP/workflows/src/create-grp-ecs.cxx +++ b/Detectors/GRP/workflows/src/create-grp-ecs.cxx @@ -268,10 +268,10 @@ int main(int argc, char** argv) add_option("run,r", bpo::value(), "run number"); add_option("run-type,t", bpo::value()->default_value(int(GRPECSObject::RunType::NONE)), "run type"); add_option("hbf-per-tf,n", bpo::value()->default_value(128), "number of HBFs per TF"); - add_option("detectors,d", bpo::value()->default_value("all"), "comma separated list of detectors"); - add_option("continuous,c", bpo::value()->default_value("ITS,TPC,TOF,MFT,MCH,MID,ZDC,FT0,FV0,FDD,CTP"), "comma separated list of detectors in continuous readout mode"); - add_option("triggering,g", bpo::value()->default_value("FT0,FV0"), "comma separated list of detectors providing a trigger"); - add_option("flps,f", bpo::value()->default_value(""), "comma separated list of FLPs in the data taking"); + add_option("detectors,d", bpo::value()->default_value("all"), "comma separated list of detectors"); + add_option("continuous,c", bpo::value()->default_value("ITS,TPC,TOF,MFT,MCH,MID,ZDC,FT0,FV0,FDD,CTP"), "comma separated list of detectors in continuous readout mode"); + add_option("triggering,g", bpo::value()->default_value("FT0,FV0"), "comma separated list of detectors providing a trigger"); + add_option("flps,f", bpo::value()->default_value(""), "comma separated list of FLPs in the data taking"); add_option("start-time,s", bpo::value()->default_value(0), "ECS run start time in ms, now() if 0"); add_option("end-time,e", bpo::value()->default_value(0), "ECS run end time in ms, start-time+3days is used if 0"); add_option("start-time-ctp", bpo::value()->default_value(0), "run start CTP time in ms, same as ECS if not set or 0"); @@ -279,7 +279,7 @@ int main(int argc, char** argv) add_option("ccdb-server", bpo::value()->default_value("http://alice-ccdb.cern.ch"), "CCDB server for upload, local file if empty"); add_option("ccdb-server-input", bpo::value()->default_value(""), "CCDB server for inputs (if needed, e.g. CTPConfig), dy default ccdb-server is used"); add_option("meta-data,m", bpo::value()->default_value("")->implicit_value(""), "metadata as key1=value1;key2=value2;.."); - add_option("refresh", bpo::value()->default_value("")->implicit_value("async"), R"(refresh server cache after upload: "none" (or ""), "async" (non-blocking) and "sync" (blocking))"); + add_option("refresh", bpo::value()->default_value("")->implicit_value("async"), R"(refresh server cache after upload: "none" (or ""), "async" (non-blocking) and "sync" (blocking))"); add_option("marginSOR", bpo::value()->default_value(4 * o2::ccdb::CcdbObjectInfo::DAY), "validity at SOR"); add_option("marginEOR", bpo::value()->default_value(10 * o2::ccdb::CcdbObjectInfo::MINUTE), "validity margin to add after EOR"); add_option("original-run,o", bpo::value()->default_value(0), "if >0, use as the source run to create CTP/Config/Config object"); @@ -313,7 +313,7 @@ int main(int argc, char** argv) std::cerr << opt_general << std::endl; exit(3); } - std::string refreshStr = vm["refresh"].as(); + std::string refreshStr = vm["refresh"].as(); CCDBRefreshMode refresh = CCDBRefreshMode::NONE; if (!refreshStr.empty() && refreshStr != "none") { if (refreshStr == "async") { diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchCosmics.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchCosmics.h index 7720d75590475..9aad1a820d08b 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchCosmics.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchCosmics.h @@ -26,7 +26,6 @@ #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 @@ -38,7 +37,7 @@ class VDriftCorrFact; } namespace gpu { -class CorrectionMapsHelper; +class TPCFastTransformPOD; } namespace globaltracking { @@ -85,7 +84,7 @@ class MatchCosmics GTrackID origID; ///< track origin id int matchID = MinusOne; ///< entry (none if MinusOne) of its match in the vector of matches }; - void setTPCCorrMaps(o2::gpu::CorrectionMapsHelper* maph); + void setTPCCorrMaps(const o2::gpu::TPCFastTransformPOD* maph); void setTPCVDrift(const o2::tpc::VDriftCorrFact& v); void setITSROFrameLengthMUS(float fums) { mITSROFrameLengthMUS = fums; } void setITSDict(const o2::itsmft::TopologyDictionary* dict) { mITSDict = dict; } @@ -138,14 +137,14 @@ class MatchCosmics std::vector mRecords; std::vector mWinners; const o2::itsmft::TopologyDictionary* mITSDict = nullptr; // cluster patterns dictionary - o2::gpu::CorrectionMapsHelper* mTPCCorrMapsHelper = nullptr; + const o2::gpu::TPCFastTransformPOD* mTPCCorrMaps = nullptr; int mTFCount = 0; - float mTPCVDriftRef = -1.; ///< TPC nominal drift speed in cm/microseconds - float mTPCVDriftCorrFact = 1.; ///< TPC nominal correction factort (wrt ref) - float mTPCVDrift = -1.; ///< TPC drift speed in cm/microseconds + float mTPCVDriftRef = -1.; ///< TPC nominal drift speed in cm/microseconds + float mTPCVDriftCorrFact = 1.; ///< TPC nominal correction factort (wrt ref) + float mTPCVDrift = -1.; ///< TPC drift speed in cm/microseconds float mTPCDriftTimeOffset = 0.; ///< drift time offset in mus - float mTPCTBinMUS = 0.; ///< TPC time bin duration in microseconds - float mBz = 0; ///< nominal Bz + float mTPCTBinMUS = 0.; ///< TPC time bin duration in microseconds + float mBz = 0; ///< nominal Bz bool mFieldON = true; bool mUseMC = true; float mITSROFrameLengthMUS = 0.; diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchHMP.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchHMP.h index fbbadc1820ee8..308ba9e61f794 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchHMP.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchHMP.h @@ -41,7 +41,6 @@ #include "DataFormatsTPC/TrackTPC.h" #include "DataFormatsTRD/TrackTRD.h" #include "ReconstructionDataFormats/PID.h" -#include "TPCFastTransform.h" #include "CommonDataFormat/InteractionRecord.h" #include "ReconstructionDataFormats/MatchInfoHMP.h" #include "ReconstructionDataFormats/TrackHMP.h" diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h index b66e5b143a898..8447fbc42cdce 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h @@ -37,9 +37,7 @@ #include "DataFormatsTPC/TrackTPC.h" #include "DataFormatsTRD/TrackTRD.h" #include "ReconstructionDataFormats/PID.h" -#include "TPCFastTransform.h" #include "CommonDataFormat/InteractionRecord.h" -#include "CorrectionMapsHelper.h" #include "GlobalTracking/MatchTOFParams.h" // from FIT @@ -152,7 +150,7 @@ class MatchTOF std::vector& getMatchedTOFLabelsVector(trkType index) { return mOutTOFLabels[index]; } ///< get vector of TOF labels of matched tracks void setTPCVDrift(const o2::tpc::VDriftCorrFact& v); - void setTPCCorrMaps(o2::gpu::CorrectionMapsHelper* maph); + void setTPCCorrMaps(const o2::gpu::TPCFastTransformPOD* maph, float lumi); void setFIT(bool value = true) { mIsFIT = value; } static int findFITIndex(int bc, const gsl::span& FITRecPoints, unsigned long firstOrbit); @@ -292,7 +290,8 @@ class MatchTOF gsl::span mTPCRefitterOccMap; ///< externally set TPC clusters occupancy map const o2::tpc::ClusterNativeAccess* mTPCClusterIdxStruct = nullptr; ///< struct holding the TPC cluster indices - o2::gpu::CorrectionMapsHelper* mTPCCorrMapsHelper = nullptr; ///< TPC cluster transformation + const o2::gpu::TPCFastTransformPOD* mTPCCorrMaps = nullptr; ///< TPC cluster transformation + float mCTPLumi = {-1}; std::unique_ptr mTPCRefitter; ///< TPC refitter used for TPC tracks refit during the reconstruction const o2::dataformats::MCTruthContainer* mTOFClusLabels; ///< input TOF clusters MC labels (pointer to read from tree) diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h index 00f2fc157a5ec..e736f0c9c8a42 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h @@ -48,14 +48,13 @@ #include "DataFormatsTPC/ClusterNativeHelper.h" #include "DataFormatsTPC/VDriftCorrFact.h" #include "ITSReconstruction/RecoGeomHelper.h" -#include "TPCFastTransform.h" #include "GPUO2InterfaceRefit.h" #include "GPUTPCGeometry.h" #include "GlobalTracking/MatchTPCITSParams.h" #include "DataFormatsITSMFT/TopologyDictionary.h" #include "DataFormatsITSMFT/TrkClusRef.h" #include "ITSMFTReconstruction/ChipMappingITS.h" -#include "CorrectionMapsHelper.h" +#include "TPCFastTransformPOD.h" #if !defined(__CINT__) && !defined(__MAKECINT__) && !defined(__ROOTCLING__) && !defined(__CLING__) #include "MemoryResources/MemoryResources.h" #endif @@ -434,7 +433,7 @@ class MatchTPCITS mVDriftCalibOn = v; } void setTPCVDrift(const o2::tpc::VDriftCorrFact& v); - void setTPCCorrMaps(o2::gpu::CorrectionMapsHelper* maph); + void setTPCCorrMaps(const o2::gpu::TPCFastTransformPOD* maph, float lumi); ///< print settings void print() const; @@ -641,7 +640,8 @@ class MatchTPCITS float mMinITSTrackPtInv = 999.; ///< cutoff on ITS track inverse pT bool mVDriftCalibOn = false; ///< flag to produce VDrift calibration data o2::tpc::VDriftCorrFact mTPCDrift{}; - o2::gpu::CorrectionMapsHelper* mTPCCorrMapsHelper = nullptr; + const o2::gpu::TPCFastTransformPOD* mTPCCorrMaps = nullptr; + float mLumiCTP{-1}; std::unique_ptr mTPCRefitter; ///< TPC refitter used for TPC tracks refit during the reconstruction diff --git a/Detectors/GlobalTracking/src/MatchCosmics.cxx b/Detectors/GlobalTracking/src/MatchCosmics.cxx index 90964fb1c05fa..615cfcb84819b 100644 --- a/Detectors/GlobalTracking/src/MatchCosmics.cxx +++ b/Detectors/GlobalTracking/src/MatchCosmics.cxx @@ -32,7 +32,7 @@ #include "CommonConstants/GeomConstants.h" #include "DataFormatsTPC/WorkflowHelper.h" #include "DataFormatsTPC/VDriftCorrFact.h" -#include "CorrectionMapsHelper.h" +#include "TPCFastTransformPOD.h" #include #include @@ -93,10 +93,9 @@ void MatchCosmics::refitWinners(const o2::globaltracking::RecoContainer& data) std::unique_ptr tpcRefitter; if (data.inputsTPCclusters) { tpcRefitter = std::make_unique(&data.inputsTPCclusters->clusterIndex, - mTPCCorrMapsHelper, mBz, + mTPCCorrMaps, mBz, tpcClusRefs.data(), 0, tpcClusShMap.data(), tpcClusOccMap.data(), tpcClusOccMap.size(), nullptr, o2::base::Propagator::Instance()); - tpcRefitter->setTrackReferenceX(900); // disable propagation after refit by setting reference to value > 500 } const auto& itsClusters = prepareITSClusters(data); @@ -598,9 +597,9 @@ void MatchCosmics::setTPCVDrift(const o2::tpc::VDriftCorrFact& v) } //______________________________________________ -void MatchCosmics::setTPCCorrMaps(o2::gpu::CorrectionMapsHelper* maph) +void MatchCosmics::setTPCCorrMaps(const o2::gpu::TPCFastTransformPOD* maph) { - mTPCCorrMapsHelper = maph; + mTPCCorrMaps = maph; } #endif diff --git a/Detectors/GlobalTracking/src/MatchTOF.cxx b/Detectors/GlobalTracking/src/MatchTOF.cxx index 89d6f8347373d..5416a612ad1f3 100644 --- a/Detectors/GlobalTracking/src/MatchTOF.cxx +++ b/Detectors/GlobalTracking/src/MatchTOF.cxx @@ -255,9 +255,10 @@ void MatchTOF::setTPCVDrift(const o2::tpc::VDriftCorrFact& v) } //______________________________________________ -void MatchTOF::setTPCCorrMaps(o2::gpu::CorrectionMapsHelper* maph) +void MatchTOF::setTPCCorrMaps(const o2::gpu::TPCFastTransformPOD* maph, float lumi) { - mTPCCorrMapsHelper = maph; + mTPCCorrMaps = maph; + mCTPLumi = lumi; } //______________________________________________ @@ -1581,6 +1582,8 @@ void MatchTOF::doMatchingForTPC(int sec) //______________________________________________ int MatchTOF::findFITIndex(int bc, const gsl::span& FITRecPoints, unsigned long firstOrbit) { + const auto& FT0Params = o2::ft0::InteractionTag::Instance(); + if ((!mHasFillScheme) && o2::tof::Utils::hasFillScheme()) { mHasFillScheme = true; for (int ibc = 0; ibc < o2::tof::Utils::getNinteractionBC(); ibc++) { @@ -1598,6 +1601,10 @@ int MatchTOF::findFITIndex(int bc, const gsl::span& FI const int distThr = 8; for (unsigned int i = 0; i < FITRecPoints.size(); i++) { + const auto& ft = FITRecPoints[i]; + if (!FT0Params.isSelected(ft)) { + continue; + } const o2::InteractionRecord ir = FITRecPoints[i].getInteractionRecord(); if (mHasFillScheme && !mFillScheme[ir.bc]) { continue; @@ -1702,8 +1709,8 @@ void MatchTOF::BestMatches(std::vector& match matchingPair.setT0true(TOFClusWork[matchingPair.getTOFClIndex()].getT0true()); // let's check if cluster has multiple-hits (noferini) - if (TOFClusWork[matchingPair.getTOFClIndex()].getNumOfContributingChannels() > 1) { - const auto& tofcl = TOFClusWork[matchingPair.getTOFClIndex()]; + const auto& tofcl = TOFClusWork[matchingPair.getTOFClIndex()]; + if (tofcl.getNumOfContributingChannels() > 1) { // has an additional hit Up or Down (Z-dir) matchingPair.setHitPatternUpDown(tofcl.isAdditionalChannelSet(o2::tof::Cluster::kUp) || tofcl.isAdditionalChannelSet(o2::tof::Cluster::kUpLeft) || @@ -1719,6 +1726,19 @@ void MatchTOF::BestMatches(std::vector& match tofcl.isAdditionalChannelSet(o2::tof::Cluster::kDownRight) || tofcl.isAdditionalChannelSet(o2::tof::Cluster::kUpRight)); } + + // estimate collision time using FT0 info if available + ULong64_t bclongtofCal = (matchingPair.getSignal() - 10000) * o2::tof::Geo::BC_TIME_INPS_INV; + double t0Best = bclongtofCal * o2::tof::Geo::BC_TIME_INPS; // here just BC + float t0BestRes = 200; + if (FITRecPoints.size() > 0) { + int index = findFITIndex(bclongtofCal, FITRecPoints, mFirstTForbit); + if (index > -1 && FITRecPoints[index].isValidTime(1) && FITRecPoints[index].isValidTime(2)) { // require A and C + t0Best += FITRecPoints[index].getCollisionTime(0); + t0BestRes = 15; + } + } + matchingPair.setFT0Best(t0Best, t0BestRes); matchedTracks[trkTypeSplitted].push_back(matchingPair); // array of MatchInfoTOF // get fit info @@ -2066,8 +2086,9 @@ void MatchTOF::updateTimeDependentParams() mMaxInvPt = std::abs(mBz) > 0.1 ? 1. / (std::abs(mBz) * 0.05) : 999.; const auto& trackTune = TrackTuneParams::Instance(); - float scale = mTPCCorrMapsHelper->getInstLumiCTP(); + float scale = mCTPLumi; if (scale < 0.f) { + LOGP(warning, "Negative scale factor for TPC covariance correction, setting it to zero"); scale = 0.f; } mCovDiagInner = trackTune.getCovInnerTotal(scale); @@ -2147,7 +2168,7 @@ bool MatchTOF::makeConstrainedTPCTrack(int matchedID, o2::dataformats::TrackTPCT void MatchTOF::checkRefitter() { if (mTPCClusterIdxStruct) { - mTPCRefitter = std::make_unique(mTPCClusterIdxStruct, mTPCCorrMapsHelper, mBz, + mTPCRefitter = std::make_unique(mTPCClusterIdxStruct, mTPCCorrMaps, mBz, mTPCTrackClusIdx.data(), 0, mTPCRefitterShMap.data(), mTPCRefitterOccMap.data(), mTPCRefitterOccMap.size(), nullptr, o2::base::Propagator::Instance()); } diff --git a/Detectors/GlobalTracking/src/MatchTPCITS.cxx b/Detectors/GlobalTracking/src/MatchTPCITS.cxx index c8c9dda6a4025..1457790c7c531 100644 --- a/Detectors/GlobalTracking/src/MatchTPCITS.cxx +++ b/Detectors/GlobalTracking/src/MatchTPCITS.cxx @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "GPUO2Interface.h" // Needed for propper settings in GPUParam.h +#include "GPUO2ExternalUser.h" // Needed for propper settings in GPUParam.h #include "GPUParam.h" #include "GPUParam.inc" #ifdef WITH_OPENMP @@ -101,7 +101,7 @@ void MatchTPCITS::run(const o2::globaltracking::RecoContainer& inp, break; } if (mVDriftCalibOn) { // in the beginning of the output vector we send the full and reference VDrift used for this TF - calib.emplace_back(mTPCVDrift, mTPCDrift.refVDrift, -999.); + calib.emplace_back(mTPCVDrift, mTPCDrift.refVDrift, mTPCDrift.refTP); calib.emplace_back(mTPCDriftTimeOffset, mTPCDrift.refTimeOffset, -999.); } @@ -205,9 +205,10 @@ void MatchTPCITS::setTPCVDrift(const o2::tpc::VDriftCorrFact& v) } //______________________________________________ -void MatchTPCITS::setTPCCorrMaps(o2::gpu::CorrectionMapsHelper* maph) +void MatchTPCITS::setTPCCorrMaps(const o2::gpu::TPCFastTransformPOD* maph, float lumi) { - mTPCCorrMapsHelper = maph; + mTPCCorrMaps = maph; + mLumiCTP = lumi; } //______________________________________________ @@ -245,8 +246,8 @@ void MatchTPCITS::init() } #endif - if (mParams->runAfterBurner) { // only used in AfterBurner - mRGHelper.init(); // prepare helper for TPC track / ITS clusters matching + if (mParams->runAfterBurner) { // only used in AfterBurner + mRGHelper.init(mParams->lowestLayerAB); // prepare helper for TPC track / ITS clusters matching } clear(); @@ -286,8 +287,9 @@ void MatchTPCITS::updateTimeDependentParams() mTPCmeanX0Inv = matbd.meanX2X0 / matbd.length; const auto& trackTune = TrackTuneParams::Instance(); - float scale = mTPCCorrMapsHelper->getInstLumiCTP(); + float scale = mLumiCTP; if (scale < 0.f) { + LOGP(warning, "Negative scale factor for TPC covariance correction, setting it to zero"); scale = 0.f; } mCovDiagInner = trackTune.getCovInnerTotal(scale); @@ -504,8 +506,7 @@ bool MatchTPCITS::prepareTPCData() mTPCSectIndexCache[sec].reserve(100 + 1.2 * ntrW / o2::constants::math::NSectors); } - mTPCRefitter = std::make_unique(mTPCClusterIdxStruct, mTPCCorrMapsHelper, mBz, mTPCTrackClusIdx.data(), 0, mTPCRefitterShMap.data(), mTPCRefitterOccMap.data(), mTPCRefitterOccMap.size(), nullptr, o2::base::Propagator::Instance()); - mTPCRefitter->setTrackReferenceX(900); // disable propagation after refit by setting reference to value > 500 + mTPCRefitter = std::make_unique(mTPCClusterIdxStruct, mTPCCorrMaps, mBz, mTPCTrackClusIdx.data(), 0, mTPCRefitterShMap.data(), mTPCRefitterOccMap.data(), mTPCRefitterOccMap.size(), nullptr, o2::base::Propagator::Instance()); mNTPCOccBinLength = mTPCRefitter->getParam()->rec.tpc.occupancyMapTimeBins; mTBinClOcc.clear(); if (mNTPCOccBinLength > 1 && mTPCRefitterOccMap.size()) { @@ -708,7 +709,7 @@ bool MatchTPCITS::prepareITSData() mITSWork.reserve(mITSTracksArray.size()); // total N ITS clusters in TF - const auto& lastClROF = mITSClusterROFRec[nROFs - 1]; + const auto& lastClROF = mITSClusterROFRec.back(); int nITSClus = lastClROF.getFirstEntry() + lastClROF.getNEntries(); mABClusterLinkIndex.resize(nITSClus, MinusOne); for (int sec = o2::constants::math::NSectors; sec--;) { @@ -1754,21 +1755,21 @@ bool MatchTPCITS::refitABTrack(int iITSAB, const TPCABSeed& seed, pmr::vectorestimateLTFast(tofL, winLink); // guess about initial value for the track integral from the origin // refit track outward in the ITS const auto& itsClRefs = ABTrackletRefs[iITSAB]; int nclRefit = 0, ncl = itsClRefs.getNClusters(); - float chi2 = 0.f; // 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[ABTrackletClusterIDs[icl]]; float alpha = geom->getSensorRefAlpha(clus.getSensorID()), x = clus.getX(); - if (!tracOut.rotate(alpha) || + if (!tracOut.rotate(alpha, refLin, propagator->getNominalBz()) || // 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->propagateToX(tracOut, x, propagator->getNominalBz(), MaxSnp, maxStep, mUseMatCorrFlag, &tofL)) { + !propagator->propagateToX(tracOut, refLin, x, propagator->getNominalBz(), MaxSnp, maxStep, mUseMatCorrFlag, &tofL)) { break; } chi2 += tracOut.getPredictedChi2(clus); @@ -1789,7 +1790,7 @@ bool MatchTPCITS::refitABTrack(int iITSAB, const TPCABSeed& seed, pmr::vectorPropagateToXBxByBz(tracOut, xtogo, MaxSnp, 10., mUseMatCorrFlag, &tofL)) { + !propagator->PropagateToXBxByBz(tracOut, refLin, xtogo, MaxSnp, 10., mUseMatCorrFlag, &tofL)) { LOG(debug) << "Propagation to inner TPC boundary X=" << xtogo << " failed, Xtr=" << tracOut.getX() << " snp=" << tracOut.getSnp(); matchedTracks.pop_back(); // destroy failed track return false; diff --git a/Detectors/GlobalTrackingWorkflow/helpers/CMakeLists.txt b/Detectors/GlobalTrackingWorkflow/helpers/CMakeLists.txt index 8ae5378222f5d..357f16bb0c21b 100644 --- a/Detectors/GlobalTrackingWorkflow/helpers/CMakeLists.txt +++ b/Detectors/GlobalTrackingWorkflow/helpers/CMakeLists.txt @@ -41,4 +41,4 @@ o2_add_executable(track-cluster-reader COMPONENT_NAME global TARGETVARNAME targetName SOURCES src/GlobalTrackClusterReader.cxx - PUBLIC_LINK_LIBRARIES O2::GlobalTrackingWorkflowHelpers O2::DetectorsRaw) + PUBLIC_LINK_LIBRARIES O2::GlobalTrackingWorkflowHelpers O2::DetectorsRaw O2::DataFormatsITSMFT) diff --git a/Detectors/GlobalTrackingWorkflow/helpers/src/GlobalTrackClusterReader.cxx b/Detectors/GlobalTrackingWorkflow/helpers/src/GlobalTrackClusterReader.cxx index 3fc8df70fdd84..a004432643763 100644 --- a/Detectors/GlobalTrackingWorkflow/helpers/src/GlobalTrackClusterReader.cxx +++ b/Detectors/GlobalTrackingWorkflow/helpers/src/GlobalTrackClusterReader.cxx @@ -11,6 +11,7 @@ #include "GlobalTrackingWorkflowHelpers/InputHelper.h" #include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" #include "CommonUtils/ConfigurableParam.h" #include "DetectorsRaw/HBFUtilsInitializer.h" #include "Framework/CallbacksPolicy.h" @@ -37,6 +38,7 @@ void customize(std::vector& workflowOptions) {"ir-frames-its", VariantType::Bool, false, {"read ITS IR frames"}}, {"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::itsmft::DPLAlpideParamInitializer::addConfigOption(options); o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } diff --git a/Detectors/GlobalTrackingWorkflow/helpers/src/InputHelper.cxx b/Detectors/GlobalTrackingWorkflow/helpers/src/InputHelper.cxx index c6c163f4b8911..e4c1e40b3a4d3 100644 --- a/Detectors/GlobalTrackingWorkflow/helpers/src/InputHelper.cxx +++ b/Detectors/GlobalTrackingWorkflow/helpers/src/InputHelper.cxx @@ -14,6 +14,7 @@ #include "GlobalTrackingWorkflowHelpers/InputHelper.h" #include "Framework/ConfigParamRegistry.h" #include "ITSMFTWorkflow/ClusterReaderSpec.h" +#include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" #include "ITSWorkflow/TrackReaderSpec.h" #include "MFTWorkflow/TrackReaderSpec.h" #include "TPCReaderWorkflow/TrackReaderSpec.h" @@ -79,13 +80,15 @@ int InputHelper::addInputSpecs(const ConfigContext& configcontext, WorkflowSpec& specs.emplace_back(o2::its::getITSTrackReaderSpec(maskTracksMC[GID::ITS])); } if (maskClusters[GID::ITS]) { - specs.emplace_back(o2::itsmft::getITSClusterReaderSpec(maskClustersMC[GID::ITS], true)); + bool doStag = itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(configcontext); + specs.emplace_back(o2::itsmft::getITSClusterReaderSpec(maskClustersMC[GID::ITS], doStag, 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)); + bool doStag = itsmft::DPLAlpideParamInitializer::isMFTStaggeringEnabled(configcontext); + specs.emplace_back(o2::itsmft::getMFTClusterReaderSpec(maskClustersMC[GID::MFT], doStag, true)); } if (maskTracks[GID::MCH] || maskMatches[GID::MCHMID]) { specs.emplace_back(o2::mch::getTrackReaderSpec(maskTracksMC[GID::MCH] || maskTracksMC[GID::MCHMID])); diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/CosmicsMatchingSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/CosmicsMatchingSpec.h index e0e74c3058086..25553c5d56d33 100644 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/CosmicsMatchingSpec.h +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/CosmicsMatchingSpec.h @@ -20,16 +20,11 @@ using namespace o2::framework; namespace o2 { -namespace tpc -{ -struct CorrectionMapsLoaderGloOpts; -} - namespace globaltracking { /// create a processor spec -framework::DataProcessorSpec getCosmicsMatchingSpec(o2::dataformats::GlobalTrackID::mask_t src, bool useMC, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts); +framework::DataProcessorSpec getCosmicsMatchingSpec(o2::dataformats::GlobalTrackID::mask_t src, bool useMC); } // namespace globaltracking } // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexingSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexingSpec.h index b8071ae83d347..9211a9cb0c264 100644 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexingSpec.h +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexingSpec.h @@ -20,16 +20,12 @@ namespace o2 { -namespace tpc -{ -struct CorrectionMapsLoaderGloOpts; -} namespace vertexing { /// create a processor spec -o2::framework::DataProcessorSpec getSecondaryVertexingSpec(o2::dataformats::GlobalTrackID::mask_t src, bool enableCasc, bool enable3body, bool enableStrangenesTracking, bool enableCCDBParams, bool useMC, bool useGeom, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts); +o2::framework::DataProcessorSpec getSecondaryVertexingSpec(o2::dataformats::GlobalTrackID::mask_t src, bool enableCasc, bool enable3body, bool enableStrangenesTracking, bool enableCCDBParams, bool useMC, bool useGeom); } // namespace vertexing } // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TOFMatcherSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TOFMatcherSpec.h index 79a4ee0ce0360..a1102af6a1f75 100644 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TOFMatcherSpec.h +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TOFMatcherSpec.h @@ -21,15 +21,11 @@ using namespace o2::framework; namespace o2 { -namespace tpc -{ -struct CorrectionMapsLoaderGloOpts; -} namespace globaltracking { /// create a processor spec -framework::DataProcessorSpec getTOFMatcherSpec(o2::dataformats::GlobalTrackID::mask_t src, bool useMC, bool useFIT, bool tpcRefit, bool strict, float extratolerancetrd, bool pushMatchable, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, int nlanes = 1); +framework::DataProcessorSpec getTOFMatcherSpec(o2::dataformats::GlobalTrackID::mask_t src, bool useMC, bool useFIT, bool tpcRefit, bool strict, float extratolerancetrd, bool pushMatchable, bool requestCTPLumi, int nlanes = 1); } // namespace globaltracking } // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TPCITSMatchingSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TPCITSMatchingSpec.h index 4aaed7d64eec5..56240fd2c8f98 100644 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TPCITSMatchingSpec.h +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TPCITSMatchingSpec.h @@ -20,14 +20,10 @@ using namespace o2::framework; namespace o2 { -namespace tpc -{ -struct CorrectionMapsLoaderGloOpts; -} namespace globaltracking { /// create a processor spec -framework::DataProcessorSpec getTPCITSMatchingSpec(o2::dataformats::GlobalTrackID::mask_t src, bool useFT0, bool calib, bool skipTPCOnly, bool useGeom, bool useMC, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts); +framework::DataProcessorSpec getTPCITSMatchingSpec(o2::dataformats::GlobalTrackID::mask_t src, bool useFT0, bool calib, bool skipTPCOnly, bool useGeom, bool useMC, bool requestCTPLumi); } // namespace globaltracking } // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/src/CosmicsMatchingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/CosmicsMatchingSpec.cxx index 8a7611e3380a4..095ede4f6581d 100644 --- a/Detectors/GlobalTrackingWorkflow/src/CosmicsMatchingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/CosmicsMatchingSpec.cxx @@ -40,14 +40,14 @@ #include "Headers/DataHeader.h" #include "CommonDataFormat/InteractionRecord.h" #include "ITSBase/GeometryTGeo.h" -#include "ITSMFTBase/DPLAlpideParam.h" +#include "DataFormatsITSMFT/DPLAlpideParam.h" #include "DataFormatsGlobalTracking/RecoContainer.h" #include "Framework/Task.h" #include "Framework/CCDBParamSpec.h" #include "ITSMFTReconstruction/ClustererParam.h" #include "DetectorsBase/GRPGeomHelper.h" #include "TPCCalibration/VDriftHelper.h" -#include "TPCCalibration/CorrectionMapsLoader.h" +#include "TPCFastTransformPOD.h" using namespace o2::framework; using MCLabelsTr = gsl::span; @@ -62,11 +62,7 @@ namespace globaltracking class CosmicsMatchingSpec : public Task { public: - CosmicsMatchingSpec(std::shared_ptr dr, std::shared_ptr gr, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, bool useMC) : mDataRequest(dr), mGGCCDBRequest(gr), mUseMC(useMC) - { - mTPCCorrMapsLoader.setLumiScaleType(sclOpts.lumiType); - mTPCCorrMapsLoader.setLumiScaleMode(sclOpts.lumiMode); - } + CosmicsMatchingSpec(std::shared_ptr dr, std::shared_ptr gr, bool useMC) : mDataRequest(dr), mGGCCDBRequest(gr), mUseMC(useMC) {} ~CosmicsMatchingSpec() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -78,7 +74,7 @@ class CosmicsMatchingSpec : public Task std::shared_ptr mDataRequest; std::shared_ptr mGGCCDBRequest; o2::tpc::VDriftHelper mTPCVDriftHelper{}; - o2::tpc::CorrectionMapsLoader mTPCCorrMapsLoader{}; + const o2::gpu::TPCFastTransformPOD* mCorrMap{nullptr}; o2::globaltracking::MatchCosmics mMatching; // matching engine bool mUseMC = true; TStopwatch mTimer; @@ -91,7 +87,6 @@ void CosmicsMatchingSpec::init(InitContext& ic) o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); mMatching.setDebugFlag(ic.options().get("debug-tree-flags")); mMatching.setUseMC(mUseMC); - mTPCCorrMapsLoader.init(ic); // } @@ -114,7 +109,8 @@ void CosmicsMatchingSpec::updateTimeDependentParams(ProcessingContext& pc) { o2::base::GRPGeomHelper::instance().checkUpdates(pc); mTPCVDriftHelper.extractCCDBInputs(pc); - mTPCCorrMapsLoader.extractCCDBInputs(pc); + auto const& raw = pc.inputs().get("corrMap"); + mCorrMap = &gpu::TPCFastTransformPOD::get(raw); static bool initOnceDone = false; if (!initOnceDone) { // this params need to be queried only once initOnceDone = true; @@ -131,12 +127,7 @@ void CosmicsMatchingSpec::updateTimeDependentParams(ProcessingContext& pc) } mMatching.init(); } - bool updateMaps = false; - if (mTPCCorrMapsLoader.isUpdated()) { - mTPCCorrMapsLoader.acknowledgeUpdate(); - updateMaps = true; - } - mMatching.setTPCCorrMaps(&mTPCCorrMapsLoader); + mMatching.setTPCCorrMaps(mCorrMap); if (mTPCVDriftHelper.isUpdated()) { LOGP(info, "Updating TPC fast transform map with new VDrift factor of {} wrt reference {} and DriftTimeOffset correction {} wrt {} from source {}", mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, @@ -144,10 +135,6 @@ void CosmicsMatchingSpec::updateTimeDependentParams(ProcessingContext& pc) mTPCVDriftHelper.getSourceName()); mMatching.setTPCVDrift(mTPCVDriftHelper.getVDriftObject()); mTPCVDriftHelper.acknowledgeUpdate(); - updateMaps = true; - } - if (updateMaps) { - mTPCCorrMapsLoader.updateVDrift(mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, mTPCVDriftHelper.getVDriftObject().getTimeOffset()); } } @@ -159,9 +146,6 @@ void CosmicsMatchingSpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) { return; } - if (mTPCCorrMapsLoader.accountCCDBInputs(matcher, obj)) { - return; - } if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) { LOG(info) << "cluster dictionary updated"; mMatching.setITSDict((const o2::itsmft::TopologyDictionary*)obj); @@ -176,7 +160,7 @@ void CosmicsMatchingSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getCosmicsMatchingSpec(GTrackID::mask_t src, bool useMC, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts) +DataProcessorSpec getCosmicsMatchingSpec(GTrackID::mask_t src, bool useMC) { std::vector outputs; Options opts{ @@ -202,13 +186,13 @@ DataProcessorSpec getCosmicsMatchingSpec(GTrackID::mask_t src, bool useMC, const dataRequest->inputs, true); o2::tpc::VDriftHelper::requestCCDBInputs(dataRequest->inputs); - o2::tpc::CorrectionMapsLoader::requestCCDBInputs(dataRequest->inputs, opts, sclOpts); + dataRequest->inputs.emplace_back("corrMap", o2::header::gDataOriginTPC, "TPCCORRMAP", 0, Lifetime::Timeframe); return DataProcessorSpec{ "cosmics-matcher", dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, sclOpts, useMC)}, + AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, useMC)}, opts}; } diff --git a/Detectors/GlobalTrackingWorkflow/src/GlobalFwdMatchingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/GlobalFwdMatchingSpec.cxx index 03dc823c62c42..a43a1e8943739 100644 --- a/Detectors/GlobalTrackingWorkflow/src/GlobalFwdMatchingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/GlobalFwdMatchingSpec.cxx @@ -20,7 +20,7 @@ #include "Framework/CCDBParamSpec.h" #include "CommonUtils/StringUtils.h" #include "DetectorsCommonDataFormats/DetectorNameConf.h" -#include "ITSMFTBase/DPLAlpideParam.h" +#include "DataFormatsITSMFT/DPLAlpideParam.h" #include "SimulationDataFormat/MCCompLabel.h" #include "DataFormatsMFT/TrackMFT.h" #include "DataFormatsITSMFT/Cluster.h" diff --git a/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexingSpec.cxx index d71a4fad7ab78..c1d7b62bbf731 100644 --- a/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexingSpec.cxx @@ -30,7 +30,7 @@ #include "Framework/CCDBParamSpec.h" #include "Framework/DeviceSpec.h" #include "FT0Reconstruction/InteractionTag.h" -#include "ITSMFTBase/DPLAlpideParam.h" +#include "DataFormatsITSMFT/DPLAlpideParam.h" #include "DetectorsCommonDataFormats/DetID.h" #include "DetectorsVertexing/PVertexer.h" #include "DetectorsBase/GRPGeomHelper.h" @@ -197,6 +197,14 @@ void PrimaryVertexingSpec::run(ProcessingContext& pc) mVertexer.getTimeReAttach().CpuTime(), mVertexer.getTotTrials(), mVertexer.getNTZClusters(), mVertexer.getMaxTrialsPerCluster(), mVertexer.getLongestClusterTimeMS(), mVertexer.getLongestClusterMult(), mVertexer.getNIniFound(), mVertexer.getNKilledBCValid(), mVertexer.getNKilledIntCand(), mVertexer.getNKilledDebris(), mVertexer.getNKilledQuality(), mVertexer.getNKilledITSOnly()); + + static bool first = true; + if (first) { + first = false; + if (pc.services().get().inputTimesliceId == 0) { + o2::conf::ConfigurableParam::write(o2::base::NameConf::getConfigOutputFileName(pc.services().get().name, PVertexerParams::Instance().getName()), PVertexerParams::Instance().getName()); + } + } } void PrimaryVertexingSpec::endOfStream(EndOfStreamContext& ec) diff --git a/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx index 80ba5f94280a0..afce2861be2fb 100644 --- a/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx @@ -31,10 +31,9 @@ #include "DetectorsBase/GlobalParams.h" #include "TStopwatch.h" #include "TPCCalibration/VDriftHelper.h" -#include "TPCCalibration/CorrectionMapsLoader.h" +#include "TPCFastTransformPOD.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/DeviceSpec.h" -#include "TPCCalibration/CorrectionMapsLoader.h" using namespace o2::framework; @@ -58,11 +57,7 @@ namespace o2d = o2::dataformats; class SecondaryVertexingSpec : public Task { public: - SecondaryVertexingSpec(std::shared_ptr dr, std::shared_ptr gr, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, GTrackID::mask_t src, bool enabCasc, bool enable3body, bool enableStrangenessTracking, bool enableCCDBParams, bool useMC) : mDataRequest(dr), mGGCCDBRequest(gr), mSrc(src), mEnableCascades(enabCasc), mEnable3BodyVertices(enable3body), mEnableStrangenessTracking(enableStrangenessTracking), mEnableCCDBParams(enableCCDBParams), mUseMC(useMC) - { - mTPCCorrMapsLoader.setLumiScaleType(sclOpts.lumiType); - mTPCCorrMapsLoader.setLumiScaleMode(sclOpts.lumiMode); - } + SecondaryVertexingSpec(std::shared_ptr dr, std::shared_ptr gr, GTrackID::mask_t src, bool enabCasc, bool enable3body, bool enableStrangenessTracking, bool enableCCDBParams, bool useMC) : mDataRequest(dr), mGGCCDBRequest(gr), mSrc(src), mEnableCascades(enabCasc), mEnable3BodyVertices(enable3body), mEnableStrangenessTracking(enableStrangenessTracking), mEnableCCDBParams(enableCCDBParams), mUseMC(useMC) {} ~SecondaryVertexingSpec() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -74,7 +69,7 @@ class SecondaryVertexingSpec : public Task std::shared_ptr mDataRequest; std::shared_ptr mGGCCDBRequest; o2::tpc::VDriftHelper mTPCVDriftHelper{}; - o2::tpc::CorrectionMapsLoader mTPCCorrMapsLoader{}; + const o2::gpu::TPCFastTransformPOD* mTPCCorrMaps{nullptr}; GTrackID::mask_t mSrc{}; bool mEnableCCDBParams = false; bool mEnableCascades = false; @@ -104,9 +99,6 @@ void SecondaryVertexingSpec::init(InitContext& ic) mStrTracker.setMCTruthOn(mUseMC); mVertexer.setStrangenessTracker(&mStrTracker); } - if (mSrc[GTrackID::TPC]) { - mTPCCorrMapsLoader.init(ic); - } } void SecondaryVertexingSpec::run(ProcessingContext& pc) @@ -127,6 +119,17 @@ void SecondaryVertexingSpec::run(ProcessingContext& pc) mVertexer.getNV0s(), calls[0] - fitCalls[0], mVertexer.getNCascades(), calls[1] - fitCalls[1], mVertexer.getN3Bodies(), calls[2] - fitCalls[2], mVertexer.getNStrangeTracks(), mTimer.CpuTime() - timeCPU0, mTimer.RealTime() - timeReal0); fitCalls = calls; + + static bool first = true; + if (first) { + first = false; + if (pc.services().get().inputTimesliceId == 0) { + o2::conf::ConfigurableParam::write(o2::base::NameConf::getConfigOutputFileName(pc.services().get().name, SVertexerParams::Instance().getName()), SVertexerParams::Instance().getName()); + if (mEnableStrangenessTracking) { + o2::conf::ConfigurableParam::write(o2::base::NameConf::getConfigOutputFileName(pc.services().get().name, o2::strangeness_tracking::StrangenessTrackingParamConfig::Instance().getName()), o2::strangeness_tracking::StrangenessTrackingParamConfig::Instance().getName()); + } + } + } } void SecondaryVertexingSpec::endOfStream(EndOfStreamContext& ec) @@ -143,9 +146,6 @@ void SecondaryVertexingSpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* ob if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) { return; } - if (mTPCCorrMapsLoader.accountCCDBInputs(matcher, obj)) { - return; - } if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) { LOG(info) << "cluster dictionary updated"; mStrTracker.setClusterDictionaryITS((const o2::itsmft::TopologyDictionary*)obj); @@ -179,7 +179,8 @@ void SecondaryVertexingSpec::updateTimeDependentParams(ProcessingContext& pc) o2::base::GRPGeomHelper::instance().checkUpdates(pc); if (mSrc[GTrackID::TPC]) { mTPCVDriftHelper.extractCCDBInputs(pc); - mTPCCorrMapsLoader.extractCCDBInputs(pc); + auto const& raw = pc.inputs().get("corrMap"); + mTPCCorrMaps = &gpu::TPCFastTransformPOD::get(raw); } static bool initOnceDone = false; if (!initOnceDone) { // this params need to be queried only once @@ -209,12 +210,8 @@ void SecondaryVertexingSpec::updateTimeDependentParams(ProcessingContext& pc) } // we may have other params which need to be queried regularly if (mSrc[GTrackID::TPC]) { - bool updateMaps = false; - if (mTPCCorrMapsLoader.isUpdated()) { - mTPCCorrMapsLoader.acknowledgeUpdate(); - updateMaps = true; - } - mVertexer.setTPCCorrMaps(&mTPCCorrMapsLoader); + mVertexer.setTPCCorrMaps(mTPCCorrMaps); + if (mTPCVDriftHelper.isUpdated()) { LOGP(info, "Updating TPC fast transform map with new VDrift factor of {} wrt reference {} and DriftTimeOffset correction {} wrt {} from source {}", mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, @@ -222,10 +219,6 @@ void SecondaryVertexingSpec::updateTimeDependentParams(ProcessingContext& pc) mTPCVDriftHelper.getSourceName()); mVertexer.setTPCVDrift(mTPCVDriftHelper.getVDriftObject()); mTPCVDriftHelper.acknowledgeUpdate(); - updateMaps = true; - } - if (updateMaps) { - mTPCCorrMapsLoader.updateVDrift(mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, mTPCVDriftHelper.getVDriftObject().getTimeOffset()); } } if (mEnableStrangenessTracking) { @@ -239,7 +232,7 @@ void SecondaryVertexingSpec::updateTimeDependentParams(ProcessingContext& pc) } DataProcessorSpec getSecondaryVertexingSpec(GTrackID::mask_t src, bool enableCasc, bool enable3body, bool enableStrangenesTracking, bool enableCCDBParams, - bool useMC, bool useGeom, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts) + bool useMC, bool useGeom) { std::vector outputs; Options opts{ @@ -254,7 +247,7 @@ DataProcessorSpec getSecondaryVertexingSpec(GTrackID::mask_t src, bool enableCas src |= (srcClus = GTrackID::getSourceMask(GTrackID::ITS)); } if (GTrackID::includesDet(o2::detectors::DetID::TPC, src) && !src[GTrackID::TPC]) { - throw std::runtime_error("Tracks involving TPC were requested w/o requesting TPC-only tracks"); + LOGP(warn, "Tracks involving TPC were requested w/o requesting TPC-only tracks, simplified selection will be applied"); } if (src[GTrackID::TPC]) { srcClus |= GTrackID::getSourceMask(GTrackID::TPC); @@ -283,7 +276,7 @@ DataProcessorSpec getSecondaryVertexingSpec(GTrackID::mask_t src, bool enableCas } if (src[GTrackID::TPC]) { o2::tpc::VDriftHelper::requestCCDBInputs(dataRequest->inputs); - o2::tpc::CorrectionMapsLoader::requestCCDBInputs(dataRequest->inputs, opts, sclOpts); + dataRequest->inputs.emplace_back("corrMap", o2::header::gDataOriginTPC, "TPCCORRMAP", 0, Lifetime::Timeframe); } outputs.emplace_back("GLO", "V0S_IDX", 0, Lifetime::Timeframe); // found V0s indices outputs.emplace_back("GLO", "V0S", 0, Lifetime::Timeframe); // found V0s @@ -310,7 +303,7 @@ DataProcessorSpec getSecondaryVertexingSpec(GTrackID::mask_t src, bool enableCas "secondary-vertexing", dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, sclOpts, src, enableCasc, enable3body, enableStrangenesTracking, enableCCDBParams, useMC)}, + AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, src, enableCasc, enable3body, enableStrangenesTracking, enableCCDBParams, useMC)}, opts}; } diff --git a/Detectors/GlobalTrackingWorkflow/src/StrangenessTrackingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/StrangenessTrackingSpec.cxx index 849964aeaf871..e313940b0a91e 100644 --- a/Detectors/GlobalTrackingWorkflow/src/StrangenessTrackingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/StrangenessTrackingSpec.cxx @@ -17,10 +17,8 @@ #include "DataFormatsGlobalTracking/RecoContainer.h" #include "StrangenessTracking/StrangenessTrackingConfigParam.h" #include "GlobalTrackingWorkflow/StrangenessTrackingSpec.h" -#include "ITSWorkflow/ClusterWriterSpec.h" #include "ITSWorkflow/TrackerSpec.h" #include "ITSWorkflow/TrackReaderSpec.h" -#include "ITSMFTWorkflow/ClusterReaderSpec.h" #include "Framework/CCDBParamSpec.h" #include "DataFormatsParameters/GRPObject.h" diff --git a/Detectors/GlobalTrackingWorkflow/src/TOFMatcherSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/TOFMatcherSpec.cxx index 4710302e4e91e..746e572c506b8 100644 --- a/Detectors/GlobalTrackingWorkflow/src/TOFMatcherSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/TOFMatcherSpec.cxx @@ -22,8 +22,9 @@ #include "DataFormatsGlobalTracking/RecoContainer.h" #include "Framework/Task.h" #include "Framework/DataProcessorSpec.h" +#include "Framework/DeviceSpec.h" #include "TPCCalibration/VDriftHelper.h" -#include "TPCCalibration/CorrectionMapsLoader.h" +#include "TPCFastTransformPOD.h" // from Tracks #include "ReconstructionDataFormats/GlobalTrackID.h" @@ -58,11 +59,7 @@ namespace globaltracking class TOFMatcherSpec : public Task { public: - TOFMatcherSpec(std::shared_ptr dr, std::shared_ptr gr, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, bool useMC, bool useFIT, bool tpcRefit, bool strict, bool pushMatchable, int lanes = 1) : mDataRequest(dr), mGGCCDBRequest(gr), mUseMC(useMC), mUseFIT(useFIT), mDoTPCRefit(tpcRefit), mStrict(strict), mPushMatchable(pushMatchable), mNlanes(lanes) - { - mTPCCorrMapsLoader.setLumiScaleType(sclOpts.lumiType); - mTPCCorrMapsLoader.setLumiScaleMode(sclOpts.lumiMode); - } + TOFMatcherSpec(std::shared_ptr dr, std::shared_ptr gr, bool useMC, bool useFIT, bool tpcRefit, bool strict, bool pushMatchable, int lanes = 1, bool requestCTPLumi = false) : mDataRequest(dr), mGGCCDBRequest(gr), mUseMC(useMC), mUseFIT(useFIT), mDoTPCRefit(tpcRefit), mStrict(strict), mPushMatchable(pushMatchable), mNlanes(lanes), mRequestCTPLumi(requestCTPLumi) {} ~TOFMatcherSpec() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -74,7 +71,7 @@ class TOFMatcherSpec : public Task std::shared_ptr mDataRequest; std::shared_ptr mGGCCDBRequest; o2::tpc::VDriftHelper mTPCVDriftHelper{}; - o2::tpc::CorrectionMapsLoader mTPCCorrMapsLoader{}; + const o2::gpu::TPCFastTransformPOD* mTPCCorrMaps = nullptr; bool mUseMC = true; bool mUseFIT = false; bool mDoTPCRefit = false; @@ -82,6 +79,7 @@ class TOFMatcherSpec : public Task bool mPushMatchable = false; float mExtraTolTRD = 0.; int mNlanes = 1; + bool mRequestCTPLumi = false; MatchTOF mMatcher; ///< Cluster finder TStopwatch mTimer; }; @@ -94,7 +92,6 @@ void TOFMatcherSpec::init(InitContext& ic) if (mStrict) { mMatcher.setHighPurity(); } - mTPCCorrMapsLoader.init(ic); mMatcher.storeMatchable(mPushMatchable); mMatcher.setExtraTimeToleranceTRD(mExtraTolTRD); mMatcher.setNlanes(mNlanes); @@ -104,7 +101,9 @@ void TOFMatcherSpec::updateTimeDependentParams(ProcessingContext& pc) { o2::base::GRPGeomHelper::instance().checkUpdates(pc); mTPCVDriftHelper.extractCCDBInputs(pc); - mTPCCorrMapsLoader.extractCCDBInputs(pc); + auto const& raw = pc.inputs().get("corrMap"); + mTPCCorrMaps = &o2::gpu::TPCFastTransformPOD::get(raw); + float lumiCTP = mRequestCTPLumi ? pc.inputs().get("lumiCTP") : 0; static bool initOnceDone = false; if (!initOnceDone) { // this params need to be queried only once const auto bcs = o2::base::GRPGeomHelper::instance().getGRPLHCIF()->getBunchFilling().getFilledBCs(); @@ -114,13 +113,7 @@ void TOFMatcherSpec::updateTimeDependentParams(ProcessingContext& pc) initOnceDone = true; // put here init-once stuff } - // we may have other params which need to be queried regularly - bool updateMaps = false; - if (mTPCCorrMapsLoader.isUpdated()) { - mTPCCorrMapsLoader.acknowledgeUpdate(); - updateMaps = true; - } - mMatcher.setTPCCorrMaps(&mTPCCorrMapsLoader); + mMatcher.setTPCCorrMaps(mTPCCorrMaps, lumiCTP); if (mTPCVDriftHelper.isUpdated()) { LOGP(info, "Updating TPC fast transform map with new VDrift factor of {} wrt reference {} and DriftTimeOffset correction {} wrt {} from source {}", mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, @@ -128,10 +121,6 @@ void TOFMatcherSpec::updateTimeDependentParams(ProcessingContext& pc) mTPCVDriftHelper.getSourceName()); mMatcher.setTPCVDrift(mTPCVDriftHelper.getVDriftObject()); mTPCVDriftHelper.acknowledgeUpdate(); - updateMaps = true; - } - if (updateMaps) { - mTPCCorrMapsLoader.updateVDrift(mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, mTPCVDriftHelper.getVDriftObject().getTimeOffset()); } } @@ -143,9 +132,6 @@ void TOFMatcherSpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) { return; } - if (mTPCCorrMapsLoader.accountCCDBInputs(matcher, obj)) { - return; - } } void TOFMatcherSpec::run(ProcessingContext& pc) @@ -228,6 +214,14 @@ void TOFMatcherSpec::run(ProcessingContext& pc) pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MATCHABLES_17", 0}, mMatcher.getMatchedTracksPair(17)); } + static bool first = true; + if (first) { + first = false; + if (pc.services().get().inputTimesliceId == 0) { + o2::conf::ConfigurableParam::write(o2::base::NameConf::getConfigOutputFileName(pc.services().get().name, MatchTOFParams::Instance().getName()), MatchTOFParams::Instance().getName()); + } + } + mTimer.Stop(); } @@ -237,7 +231,7 @@ void TOFMatcherSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getTOFMatcherSpec(GID::mask_t src, bool useMC, bool useFIT, bool tpcRefit, bool strict, float extratolerancetrd, bool pushMatchable, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, int nlanes) +DataProcessorSpec getTOFMatcherSpec(GID::mask_t src, bool useMC, bool useFIT, bool tpcRefit, bool strict, float extratolerancetrd, bool pushMatchable, bool requestCTPLumi, int nlanes) { uint32_t ss = o2::globaltracking::getSubSpec(strict ? o2::globaltracking::MatchingType::Strict : o2::globaltracking::MatchingType::Standard); Options opts; @@ -263,7 +257,10 @@ DataProcessorSpec getTOFMatcherSpec(GID::mask_t src, bool useMC, bool useFIT, bo dataRequest->inputs, true); o2::tpc::VDriftHelper::requestCCDBInputs(dataRequest->inputs); - o2::tpc::CorrectionMapsLoader::requestCCDBInputs(dataRequest->inputs, opts, sclOpts); + dataRequest->inputs.emplace_back("corrMap", o2::header::gDataOriginTPC, "TPCCORRMAP", 0, Lifetime::Timeframe); + if (requestCTPLumi) { + dataRequest->inputs.emplace_back("lumiCTP", o2::header::gDataOriginCTP, "LUMICTP", 0, Lifetime::Timeframe); + } std::vector outputs; if (GID::includesSource(GID::TPC, src)) { outputs.emplace_back(o2::header::gDataOriginTOF, "MTC_TPC", ss, Lifetime::Timeframe); @@ -317,7 +314,7 @@ DataProcessorSpec getTOFMatcherSpec(GID::mask_t src, bool useMC, bool useFIT, bo "tof-matcher", dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, sclOpts, useMC, useFIT, tpcRefit, strict, pushMatchable, nlanes)}, + AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, useMC, useFIT, tpcRefit, strict, pushMatchable, nlanes, requestCTPLumi)}, opts}; } diff --git a/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx index 1368bf6f34fe4..079fe5455fd4a 100644 --- a/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx @@ -39,7 +39,7 @@ #include "DetectorsBase/GeometryManager.h" #include "DetectorsBase/Propagator.h" #include "DetectorsBase/GlobalParams.h" -#include "ITSMFTBase/DPLAlpideParam.h" +#include "DataFormatsITSMFT/DPLAlpideParam.h" #include "ITSBase/GeometryTGeo.h" #include "GlobalTracking/MatchTPCITSParams.h" #include "DetectorsCommonDataFormats/DetectorNameConf.h" @@ -50,7 +50,7 @@ #include "ITSMFTReconstruction/ClustererParam.h" #include "DetectorsBase/GRPGeomHelper.h" #include "TPCCalibration/VDriftHelper.h" -#include "TPCCalibration/CorrectionMapsLoader.h" +#include "TPCFastTransformPOD.h" #ifdef ENABLE_UPGRADES #include "ITS3Reconstruction/TopologyDictionary.h" @@ -69,13 +69,9 @@ namespace globaltracking class TPCITSMatchingDPL : public Task { public: - TPCITSMatchingDPL(std::shared_ptr dr, std::shared_ptr gr, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, - bool useFT0, bool calib, bool skipTPCOnly, bool useMC) - : mDataRequest(dr), mGGCCDBRequest(gr), mUseFT0(useFT0), mCalibMode(calib), mSkipTPCOnly(skipTPCOnly), mUseMC(useMC) - { - mTPCCorrMapsLoader.setLumiScaleType(sclOpts.lumiType); - mTPCCorrMapsLoader.setLumiScaleMode(sclOpts.lumiMode); - } + TPCITSMatchingDPL(std::shared_ptr dr, std::shared_ptr gr, + bool useFT0, bool calib, bool skipTPCOnly, bool useMC, bool requestCTPLumi) + : mDataRequest(dr), mGGCCDBRequest(gr), mUseFT0(useFT0), mCalibMode(calib), mSkipTPCOnly(skipTPCOnly), mUseMC(useMC), mRequestCTPLumi(requestCTPLumi) {} ~TPCITSMatchingDPL() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -87,12 +83,13 @@ class TPCITSMatchingDPL : public Task std::shared_ptr mDataRequest; std::shared_ptr mGGCCDBRequest; o2::tpc::VDriftHelper mTPCVDriftHelper{}; - o2::tpc::CorrectionMapsLoader mTPCCorrMapsLoader{}; + const o2::gpu::TPCFastTransformPOD* mTPCCorrMaps{}; o2::globaltracking::MatchTPCITS mMatching; // matching engine bool mUseFT0 = false; bool mCalibMode = false; bool mSkipTPCOnly = false; // to use only externally constrained tracks (for test only) bool mUseMC = true; + bool mRequestCTPLumi = false; TStopwatch mTimer; }; @@ -107,7 +104,6 @@ void TPCITSMatchingDPL::init(InitContext& ic) mMatching.setNThreads(std::max(1, ic.options().get("nthreads"))); mMatching.setUseBCFilling(!ic.options().get("ignore-bc-check")); mMatching.setDebugFlag(ic.options().get("debug-tree-flags")); - mTPCCorrMapsLoader.init(ic); } void TPCITSMatchingDPL::run(ProcessingContext& pc) @@ -129,6 +125,14 @@ void TPCITSMatchingDPL::run(ProcessingContext& pc) mMatching.run(recoData, matchedTracks, ABTrackletRefs, ABTrackletClusterIDs, matchLabels, ABTrackletLabels, calib); + static bool first = true; + if (first) { + first = false; + if (pc.services().get().inputTimesliceId == 0) { + o2::conf::ConfigurableParam::write(o2::base::NameConf::getConfigOutputFileName(pc.services().get().name, MatchTPCITSParams::Instance().getName()), MatchTPCITSParams::Instance().getName()); + } + } + mTimer.Stop(); } @@ -148,9 +152,6 @@ void TPCITSMatchingDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) { return; } - if (mTPCCorrMapsLoader.accountCCDBInputs(matcher, obj)) { - return; - } if (matcher == ConcreteDataMatcher("GLO", "ITSTPCPARAM", 0)) { LOG(info) << "ITS-TPC Matching params updated from ccdb"; return; @@ -184,7 +185,10 @@ void TPCITSMatchingDPL::updateTimeDependentParams(ProcessingContext& pc) { o2::base::GRPGeomHelper::instance().checkUpdates(pc); mTPCVDriftHelper.extractCCDBInputs(pc); - mTPCCorrMapsLoader.extractCCDBInputs(pc); + auto const& raw = pc.inputs().get("corrMap"); + mTPCCorrMaps = &o2::gpu::TPCFastTransformPOD::get(raw); + float lumiCTP = mRequestCTPLumi ? pc.inputs().get("lumiCTP") : 0; + static bool initOnceDone = false; if (!initOnceDone) { // this params need to be queried only once initOnceDone = true; @@ -218,29 +222,20 @@ void TPCITSMatchingDPL::updateTimeDependentParams(ProcessingContext& pc) LOGP(fatal, "USEMatCorrTGeo cannot work w/o full geometry request in the GRPGeomHelper"); } } - // we may have other params which need to be queried regularly - bool updateMaps = false; - if (mTPCCorrMapsLoader.isUpdated()) { - mTPCCorrMapsLoader.acknowledgeUpdate(); - updateMaps = true; - } - mMatching.setTPCCorrMaps(&mTPCCorrMapsLoader); + + mMatching.setTPCCorrMaps(mTPCCorrMaps, lumiCTP); if (mTPCVDriftHelper.isUpdated()) { - LOGP(info, "Updating TPC fast transform map with new VDrift factor of {} wrt reference {} and DriftTimeOffset correction {} wrt {} from source {}", + LOGP(info, "Updating TPC VDrift: corrFact {} wrt refVDrift {} and DriftTimeOffset correction {} wrt {} from source {}", mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, mTPCVDriftHelper.getVDriftObject().timeOffsetCorr, mTPCVDriftHelper.getVDriftObject().refTimeOffset, mTPCVDriftHelper.getSourceName()); mMatching.setTPCVDrift(mTPCVDriftHelper.getVDriftObject()); mTPCVDriftHelper.acknowledgeUpdate(); - updateMaps = true; - } - if (updateMaps) { - mTPCCorrMapsLoader.updateVDrift(mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, mTPCVDriftHelper.getVDriftObject().getTimeOffset()); } } -DataProcessorSpec getTPCITSMatchingSpec(GTrackID::mask_t src, bool useFT0, bool calib, bool skipTPCOnly, bool useGeom, bool useMC, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts) +DataProcessorSpec getTPCITSMatchingSpec(GTrackID::mask_t src, bool useFT0, bool calib, bool skipTPCOnly, bool useGeom, bool useMC, bool requestCTPLumi) { std::vector outputs; auto dataRequest = std::make_shared(); @@ -296,13 +291,15 @@ DataProcessorSpec getTPCITSMatchingSpec(GTrackID::mask_t src, bool useFT0, bool {"debug-tree-flags", VariantType::Int, 0, {"DebugFlagTypes bit-pattern for debug tree"}}}; o2::tpc::VDriftHelper::requestCCDBInputs(dataRequest->inputs); - o2::tpc::CorrectionMapsLoader::requestCCDBInputs(dataRequest->inputs, opts, sclOpts); - + dataRequest->inputs.emplace_back("corrMap", o2::header::gDataOriginTPC, "TPCCORRMAP", 0, Lifetime::Timeframe); + if (requestCTPLumi) { + dataRequest->inputs.emplace_back("lumiCTP", o2::header::gDataOriginCTP, "LUMICTP", 0, Lifetime::Timeframe); + } return DataProcessorSpec{ "itstpc-track-matcher", dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, sclOpts, useFT0, calib, skipTPCOnly, useMC)}, + AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, useFT0, calib, skipTPCOnly, useMC, requestCTPLumi)}, opts}; } diff --git a/Detectors/GlobalTrackingWorkflow/src/VertexTrackMatcherSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/VertexTrackMatcherSpec.cxx index f24e7c13e336f..90e4dd4b0f001 100644 --- a/Detectors/GlobalTrackingWorkflow/src/VertexTrackMatcherSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/VertexTrackMatcherSpec.cxx @@ -23,7 +23,7 @@ #include "TPCBase/ParameterElectronics.h" #include "TPCBase/ParameterDetector.h" #include "TPCCalibration/VDriftHelper.h" -#include "ITSMFTBase/DPLAlpideParam.h" +#include "DataFormatsITSMFT/DPLAlpideParam.h" #include "TStopwatch.h" using namespace o2::framework; diff --git a/Detectors/GlobalTrackingWorkflow/src/cosmics-match-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/cosmics-match-workflow.cxx index e4082bdd14d86..14812ac25cce1 100644 --- a/Detectors/GlobalTrackingWorkflow/src/cosmics-match-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/cosmics-match-workflow.cxx @@ -31,7 +31,8 @@ #include "DetectorsRaw/HBFUtilsInitializer.h" #include "Framework/CallbacksPolicy.h" #include "GlobalTrackingWorkflowHelpers/InputHelper.h" -#include "TPCCalibration/CorrectionMapsLoader.h" +#include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" +#include "TPCCalibration/CorrectionMapsOptions.h" using namespace o2::framework; using DetID = o2::detectors::DetID; @@ -52,7 +53,8 @@ void customize(std::vector& workflowOptions) {"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::tpc::CorrectionMapsLoader::addGlobalOptions(options); + o2::itsmft::DPLAlpideParamInitializer::addITSConfigOption(options); + o2::tpc::CorrectionMapsOptions::addGlobalOptions(options); o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } @@ -83,7 +85,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); // write the configuration used for the workflow o2::conf::ConfigurableParam::writeINI("o2match-cosmics-workflow_configuration.ini"); - auto sclOpt = o2::tpc::CorrectionMapsLoader::parseGlobalOptions(configcontext.options()); + auto sclOpt = o2::tpc::CorrectionMapsOptions::parseGlobalOptions(configcontext.options()); auto useMC = !configcontext.options().get("disable-mc"); auto disableRootOut = configcontext.options().get("disable-root-output"); @@ -102,10 +104,10 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) } GID::mask_t srcCl = src; GID::mask_t dummy; - if (sclOpt.needTPCScalersWorkflow() && !configcontext.options().get("disable-root-input")) { - specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt.lumiType == 2, sclOpt.enableMShapeCorrection)); + if (!configcontext.options().get("disable-root-input")) { + specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt.lumiType == o2::tpc::LumiScaleType::TPCScaler, sclOpt.enableMShapeCorrection, sclOpt)); } - specs.emplace_back(o2::globaltracking::getCosmicsMatchingSpec(src, useMC, sclOpt)); + specs.emplace_back(o2::globaltracking::getCosmicsMatchingSpec(src, useMC)); o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, src, src, src, useMC, dummy); // clusters MC is not needed diff --git a/Detectors/GlobalTrackingWorkflow/src/globalfwd-matcher-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/globalfwd-matcher-workflow.cxx index 13a842130e5d1..fd90aff5f32ff 100644 --- a/Detectors/GlobalTrackingWorkflow/src/globalfwd-matcher-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/globalfwd-matcher-workflow.cxx @@ -21,6 +21,7 @@ #include "GlobalTrackingWorkflow/MatchedMFTMCHWriterSpec.h" #include "GlobalTrackingWorkflowHelpers/InputHelper.h" #include "GlobalTracking/MatchGlobalFwdParam.h" +#include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" using namespace o2::framework; using GID = o2::dataformats::GlobalTrackID; @@ -46,6 +47,7 @@ void customize(std::vector& workflowOptions) {"disable-root-output", o2::framework::VariantType::Bool, false, {"do not write output root files"}}, {"enable-match-output", o2::framework::VariantType::Bool, false, {"stores mftmch matching info on mftmchmatches.root"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + o2::itsmft::DPLAlpideParamInitializer::addMFTConfigOption(options); o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } diff --git a/Detectors/GlobalTrackingWorkflow/src/secondary-vertexing-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/secondary-vertexing-workflow.cxx index 0ac640cbad9fd..e630a8dad72dd 100644 --- a/Detectors/GlobalTrackingWorkflow/src/secondary-vertexing-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/secondary-vertexing-workflow.cxx @@ -29,7 +29,8 @@ #include "Framework/ConfigParamSpec.h" #include "Framework/CompletionPolicyHelpers.h" #include "DetectorsBase/DPLWorkflowUtils.h" -#include "TPCCalibration/CorrectionMapsLoader.h" +#include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" +#include "TPCCalibration/CorrectionMapsOptions.h" using namespace o2::framework; using GID = o2::dataformats::GlobalTrackID; @@ -62,7 +63,8 @@ void customize(std::vector& workflowOptions) {"use-full-geometry", o2::framework::VariantType::Bool, false, {"use full geometry instead of the light-weight ITS part"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}, {"combine-source-devices", o2::framework::VariantType::Bool, false, {"merge DPL source devices"}}}; - o2::tpc::CorrectionMapsLoader::addGlobalOptions(options); + o2::itsmft::DPLAlpideParamInitializer::addITSConfigOption(options); + o2::tpc::CorrectionMapsOptions::addGlobalOptions(options); o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } @@ -86,7 +88,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto enable3body = !configcontext.options().get("disable-3body-finder"); auto enableStrTr = !configcontext.options().get("disable-strangeness-tracker"); auto useGeom = configcontext.options().get("use-full-geometry"); - auto sclOpt = o2::tpc::CorrectionMapsLoader::parseGlobalOptions(configcontext.options()); + auto sclOpt = o2::tpc::CorrectionMapsOptions::parseGlobalOptions(configcontext.options()); GID::mask_t src = allowedSources & GID::getSourcesMask(configcontext.options().get("vertexing-sources")); GID::mask_t dummy, srcClus = GID::includesDet(DetID::TOF, src) ? GID::getSourceMask(GID::TOF) : dummy; // eventually, TPC clusters will be needed for refit if (enableStrTr) { @@ -94,15 +96,15 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) } if (src[GID::TPC]) { srcClus |= GID::getSourceMask(GID::TPC); - } - if (sclOpt.requestCTPLumi) { - src = src | GID::getSourcesMask("CTP"); + if (sclOpt.requestCTPLumi) { + src = src | GID::getSourcesMask("CTP"); + } } WorkflowSpec specs; - if (sclOpt.needTPCScalersWorkflow() && !configcontext.options().get("disable-root-input")) { - specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt.lumiType == 2, sclOpt.enableMShapeCorrection)); + if (!configcontext.options().get("disable-root-input")) { + specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt.lumiType == o2::tpc::LumiScaleType::TPCScaler, sclOpt.enableMShapeCorrection, sclOpt)); } - specs.emplace_back(o2::vertexing::getSecondaryVertexingSpec(src, enableCasc, enable3body, enableStrTr, enableCCDBParams, useMC, useGeom, sclOpt)); + specs.emplace_back(o2::vertexing::getSecondaryVertexingSpec(src, enableCasc, enable3body, enableStrTr, enableCCDBParams, useMC, useGeom)); // only TOF clusters are needed if TOF is involved, no clusters MC needed WorkflowSpec inputspecs; diff --git a/Detectors/GlobalTrackingWorkflow/src/strangeness-tracking-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/strangeness-tracking-workflow.cxx index bdc1af958886c..8c42871ac05bf 100644 --- a/Detectors/GlobalTrackingWorkflow/src/strangeness-tracking-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/strangeness-tracking-workflow.cxx @@ -21,6 +21,7 @@ #include "GlobalTrackingWorkflowReaders/TrackTPCITSReaderSpec.h" #include "GlobalTrackingWorkflowReaders/PrimaryVertexReaderSpec.h" #include "GlobalTrackingWorkflowHelpers/InputHelper.h" +#include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" #include "DetectorsRaw/HBFUtilsInitializer.h" #include "Framework/CallbacksPolicy.h" @@ -46,6 +47,7 @@ void customize(std::vector& workflowOptions) {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC"}}, {"use-full-geometry", o2::framework::VariantType::Bool, false, {"use full geometry instead of the light-weight ITS part"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + o2::itsmft::DPLAlpideParamInitializer::addITSConfigOption(options); o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } diff --git a/Detectors/GlobalTrackingWorkflow/src/tof-matcher-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/tof-matcher-workflow.cxx index 8dc56794817a5..96d7c783022c3 100644 --- a/Detectors/GlobalTrackingWorkflow/src/tof-matcher-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/tof-matcher-workflow.cxx @@ -32,7 +32,7 @@ #include "Steer/MCKinematicsReader.h" #include "TSystem.h" #include "DetectorsBase/DPLWorkflowUtils.h" -#include "TPCCalibration/CorrectionMapsLoader.h" +#include "TPCCalibration/CorrectionMapsOptions.h" #include "TPCWorkflow/TPCScalerSpec.h" using namespace o2::framework; @@ -70,7 +70,7 @@ void customize(std::vector& workflowOptions) {"write-matchable", o2::framework::VariantType::Bool, false, {"write all matchable pairs in a file (o2matchable_tof.root)"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}, {"combine-devices", o2::framework::VariantType::Bool, false, {"merge DPL source/writer devices"}}}; - o2::tpc::CorrectionMapsLoader::addGlobalOptions(options); + o2::tpc::CorrectionMapsOptions::addGlobalOptions(options); o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } @@ -97,7 +97,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto diagnostic = configcontext.options().get("enable-dia"); auto extratolerancetrd = configcontext.options().get("trd-extra-tolerance"); auto writeMatchable = configcontext.options().get("write-matchable"); - auto sclOpt = o2::tpc::CorrectionMapsLoader::parseGlobalOptions(configcontext.options()); + auto sclOpt = o2::tpc::CorrectionMapsOptions::parseGlobalOptions(configcontext.options()); bool writematching = 0; bool writecalib = 0; bool refitTPCTOF = configcontext.options().get("refit-tpc-tof"); @@ -114,9 +114,9 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) } } - if (!writecalib) { - useFIT = false; - } + // if (!writecalib) { + // useFIT = false; + // } LOG(debug) << "TOF MATCHER WORKFLOW configuration"; LOG(debug) << "TOF track inputs = " << configcontext.options().get("track-sources"); @@ -168,10 +168,10 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) specs.push_back(s); } } - if (sclOpt.needTPCScalersWorkflow() && !configcontext.options().get("disable-root-input")) { - specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt.lumiType == 2, sclOpt.enableMShapeCorrection)); + if (!configcontext.options().get("disable-root-input")) { + specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt.lumiType == o2::tpc::LumiScaleType::TPCScaler, sclOpt.enableMShapeCorrection, sclOpt)); } - specs.emplace_back(o2::globaltracking::getTOFMatcherSpec(src, useMC, useFIT, refitTPCTOF, strict, extratolerancetrd, writeMatchable, sclOpt, nLanes)); // doTPCrefit not yet supported (need to load TPC clusters?) + specs.emplace_back(o2::globaltracking::getTOFMatcherSpec(src, useMC, useFIT, refitTPCTOF, strict, extratolerancetrd, writeMatchable, sclOpt.requestCTPLumi, nLanes)); // doTPCrefit not yet supported (need to load TPC clusters?) if (!disableRootOut) { std::vector writers; diff --git a/Detectors/GlobalTrackingWorkflow/src/tpcits-match-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/tpcits-match-workflow.cxx index 810c7c564b4a8..78e5db9e4b391 100644 --- a/Detectors/GlobalTrackingWorkflow/src/tpcits-match-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/tpcits-match-workflow.cxx @@ -24,7 +24,8 @@ #include "Framework/CallbacksPolicy.h" #include "Framework/ConfigContext.h" #include "Framework/CompletionPolicyHelpers.h" -#include "TPCCalibration/CorrectionMapsLoader.h" +#include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" +#include "TPCCalibration/CorrectionMapsOptions.h" using namespace o2::framework; using GID = o2::dataformats::GlobalTrackID; @@ -46,7 +47,8 @@ void customize(std::vector& workflowOptions) {"produce-calibration-data", o2::framework::VariantType::Bool, false, {"produce output for TPC vdrift calibration"}}, {"use-full-geometry", o2::framework::VariantType::Bool, false, {"use full geometry instead of the light-weight ITS part"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; - o2::tpc::CorrectionMapsLoader::addGlobalOptions(options); + o2::itsmft::DPLAlpideParamInitializer::addITSConfigOption(options); + o2::tpc::CorrectionMapsOptions::addGlobalOptions(options); o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } @@ -76,7 +78,8 @@ WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& configcont GID::mask_t alowedSources = GID::getSourcesMask("ITS,TPC,TPC-TOF"); GID::mask_t src = alowedSources & GID::getSourcesMask(configcontext.options().get("track-sources")); bool needStrictTRDTOF = (src & GID::getSourcesMask("TPC-TRD,TPC-TOF,TPC-TRD-TOF")).any(); - auto sclOpt = o2::tpc::CorrectionMapsLoader::parseGlobalOptions(configcontext.options()); + auto doStag = o2::itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(configcontext); // RS at the moment is not passed to the matching w-flow + auto sclOpt = o2::tpc::CorrectionMapsOptions::parseGlobalOptions(configcontext.options()); auto useGeom = configcontext.options().get("use-full-geometry"); auto useFT0 = configcontext.options().get("use-ft0"); if (useFT0) { @@ -90,10 +93,10 @@ WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& configcont } o2::framework::WorkflowSpec specs; - if (sclOpt.needTPCScalersWorkflow() && !configcontext.options().get("disable-root-input")) { - specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt.lumiType == 2, sclOpt.enableMShapeCorrection)); + if (!configcontext.options().get("disable-root-input")) { + specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt.lumiType == o2::tpc::LumiScaleType::TPCScaler, sclOpt.enableMShapeCorrection, sclOpt)); } - specs.emplace_back(o2::globaltracking::getTPCITSMatchingSpec(srcL, useFT0, calib, !GID::includesSource(GID::TPC, src), useGeom, useMC, sclOpt)); + specs.emplace_back(o2::globaltracking::getTPCITSMatchingSpec(srcL, useFT0, calib, !GID::includesSource(GID::TPC, src), useGeom, useMC, sclOpt.requestCTPLumi)); if (!configcontext.options().get("disable-root-output")) { specs.emplace_back(o2::globaltracking::getTrackWriterTPCITSSpec(useMC)); diff --git a/Detectors/GlobalTrackingWorkflow/study/CMakeLists.txt b/Detectors/GlobalTrackingWorkflow/study/CMakeLists.txt index 398e7eb215f2e..4ee9f2f314a08 100644 --- a/Detectors/GlobalTrackingWorkflow/study/CMakeLists.txt +++ b/Detectors/GlobalTrackingWorkflow/study/CMakeLists.txt @@ -12,6 +12,7 @@ #add_compile_options(-O0 -g -fPIC) o2_add_library(GlobalTrackingStudy + TARGETVARNAME targetName SOURCES src/TPCTrackStudy.cxx src/TrackingStudy.cxx src/SVStudy.cxx @@ -23,6 +24,10 @@ o2_add_library(GlobalTrackingStudy src/TrackInfoExt.cxx src/TrackMCStudyConfig.cxx src/TrackMCStudyTypes.cxx + src/TPCClusSelector.cxx + src/CheckResidSpec.cxx + src/CheckResidConfig.cxx + src/HistoManager.cxx PUBLIC_LINK_LIBRARIES O2::GlobalTracking O2::GlobalTrackingWorkflowReaders O2::GlobalTrackingWorkflowHelpers @@ -36,6 +41,9 @@ o2_target_root_dictionary(GlobalTrackingStudy include/GlobalTrackingStudy/TrackInfoExt.h include/GlobalTrackingStudy/TrackMCStudyConfig.h include/GlobalTrackingStudy/TrackMCStudyTypes.h + include/GlobalTrackingStudy/CheckResidTypes.h + include/GlobalTrackingStudy/CheckResidConfig.h + include/GlobalTrackingStudy/HistoManager.h LINKDEF src/GlobalTrackingStudyLinkDef.h ) @@ -73,3 +81,13 @@ o2_add_executable(dump-workfow COMPONENT_NAME bc-tracks SOURCES src/track-dump-workflow.cxx PUBLIC_LINK_LIBRARIES O2::GlobalTrackingStudy) + +o2_add_executable(resid-workfow + COMPONENT_NAME check + SOURCES src/check-resid-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::GlobalTrackingStudy) + +if (OpenMP_CXX_FOUND) + target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) + target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) +endif() diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidConfig.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidConfig.h new file mode 100644 index 0000000000000..09ebba2d2e3f2 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidConfig.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 O2_CHECK_RESID_CONFIG_H +#define O2_CHECK_RESID_CONFIG_H +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +namespace o2::checkresid +{ +struct CheckResidConfig : o2::conf::ConfigurableParamHelper { + int minPVContributors = 10; + int minTPCCl = 60; + int minITSCl = 7; + float minPt = 0.4f; + float maxPt = 50.f; + float maxTgl = 2.f; + float rCompIBOB = 12.f; + + bool pvcontribOnly = true; + bool addPVAsCluster = true; + bool useStableRef = true; + bool doIBOB = true; + bool doResid = true; + + bool refitPV = true; + float refitPVMV = false; + float refitPVIniScale = 100.f; + + std::string outname{"checkResid"}; + // histogram settings + int nBinsRes = 100; + int nBinsPhi = 30; + int nBinsZ = 20; + int nBinsPt = 15; + int nBinsTgl = 20; + int minHistoStat2Fit = 1000; + float maxPull = 4; + float zranges[8] = {10.f, 15.f, 15.f, 15.f, 40.f, 40.f, 74.f, 74.f}; + float maxDYZ[8] = {0.03, 0.015, 0.01, 0.01, 0.08, 0.08, 0.12, 0.1}; + float maxDPar[5] = {0.15, 0.15, 0.015, 0.015, 1.}; + // drawing settings + float resMMLrY[8] = {0.003, 0.003, 0.003, 0.003, 0.005, 0.005, 0.005, 0.005}; + float resMMLrZ[8] = {0.002, 0.0015, 0.0015, 0.0015, 0.005, 0.005, 0.005, 0.005}; + float resMMPar[5] = {0.03, 0.01, 0.005, 0.001, 0.5}; + // + // string with existing histomanagers files to draw (comma or semicolon separated) and optional legends + std::string ext_hm_list{}; + std::string ext_leg_list{}; + + O2ParamDef(CheckResidConfig, "checkresid"); +}; +} // namespace o2::checkresid + +#endif diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/DecodedDataDumpSpec.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidSpec.h similarity index 58% rename from Detectors/MUON/MID/Workflow/include/MIDWorkflow/DecodedDataDumpSpec.h rename to Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidSpec.h index 4d104aacac15c..3cae8e94b8e68 100644 --- a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/DecodedDataDumpSpec.h +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidSpec.h @@ -9,22 +9,18 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file MIDWorkflow/RawDumpSpec.h -/// \brief Device to dump decoded raw data -/// \author Diego Stocco -/// \date 17 February 2022 - -#ifndef O2_MID_RAWDUMPSPEC_H -#define O2_MID_RAWDUMPSPEC_H +#ifndef O2_CHECK_RESID_H +#define O2_CHECK_RESID_H +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "Framework/Task.h" #include "Framework/DataProcessorSpec.h" -namespace o2 -{ -namespace mid +namespace o2::checkresid { -framework::DataProcessorSpec getRawDumpSpec(); -} // namespace mid -} // namespace o2 +/// create a processor spec +o2::framework::DataProcessorSpec getCheckResidSpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool drawOnly, bool postProcOnly); + +} // namespace o2::checkresid -#endif // O2_MID_RAWDUMPSPEC_H +#endif // O2_CHECK_RESID_H diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidTypes.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidTypes.h new file mode 100644 index 0000000000000..ebb6a7aabe9fa --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidTypes.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 O2_CHECK_RESID_TYPES_H +#define O2_CHECK_RESID_TYPES_H + +#include "ReconstructionDataFormats/Track.h" + +namespace o2::checkresid +{ +struct Point { + float dy = 0.f; + float dz = 0.f; + float sig2y = 0.f; + float sig2z = 0.f; + float phi = 0.f; + float z = 0.f; + int16_t sens = -1; + int8_t lr = -1; // -1 = vtx + ClassDefNV(Point, 1) +}; + +struct Track { + o2::dataformats::GlobalTrackID gid{}; + o2::track::TrackPar track; + o2::track::TrackParCov trIBOut; + o2::track::TrackParCov trOBInw; + std::vector points; + ClassDefNV(Track, 1) +}; + +} // namespace o2::checkresid + +#endif diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/HistoManager.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/HistoManager.h new file mode 100644 index 0000000000000..eb9cf6876333e --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/HistoManager.h @@ -0,0 +1,93 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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_HISTOMANAGER_H_ +#define _O2_HISTOMANAGER_H_ + +#include +#include +#include "TObjArray.h" + +class TH1; +class TH2; +class TH1F; +class TH2F; +class TProfile; +class TGraph; +class TFile; + +namespace o2 +{ + +class HistoManager : public TObjArray +{ + public: + HistoManager(const std::string& dirname = "", const std::string& fname = "histoman.root", bool load = kFALSE, const std::string& prefix = ""); + ~HistoManager() override { Delete(); } + + HistoManager* createClone(const std::string& prefix) const; + void addPrefix(const std::string& pref = ""); + + int getNHistos() const { return mNHistos; } + TGraph* getGraph(int id) const; + TH1* getHisto(int id) const; + TH1* getHisto(const std::string& name) const; + TH1F* getHisto1F(int id) const; + TH2F* getHisto2F(int id) const; + TProfile* getHistoP(int id) const; + + int addHisto(TH1* histo, int at = -1); + int addGraph(TGraph* gr, int at = -1); + void delHisto(int at); + + void setFile(TFile* file); + void setFileName(const std::string& fname); + const std::string& getFileName() const { return mDefName; } + void setDirName(const std::string& name) { mDirName = name; } + const std::string& getDirName() const { return mDirName; } + + void reset(); + void write(TFile* file = nullptr); + int write(const std::string& flname) + { + setFileName(flname); + write(); + return 0; + } + + void addHistos(const HistoManager* hm, Double_t c1 = 1.); + void divideHistos(const HistoManager* hm); + void multiplyHistos(const HistoManager* hm); + void scaleHistos(Double_t c1 = 1.); + void setColor(int tcolor = 1); + void setMarkerStyle(Style_t mstyle = 1, Size_t msize = 1); + void setMarkerSize(Size_t msize = 1); + void sumw2(); + int load(const std::string& fname, const std::string& dirname = ""); + + void purify(bool emptyToo = kFALSE); + + void Print(Option_t* option = "") const override; + void Clear(Option_t* option = "") override; + void Delete(Option_t* option = "") override; + void Compress() override; + + private: + int mNHistos{0}; //! Number of histograms defined + std::string mDefName{}; //! Default file name + std::string mDirName{}; //! Directory name in the output file + + ClassDefOverride(HistoManager, 0); +}; + +} // namespace o2 + +#endif // _O2_HISTOMANAGER_H_ diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TPCClusSelector.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TPCClusSelector.h new file mode 100644 index 0000000000000..c1765558458c2 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TPCClusSelector.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. + +// helper class for TPC clusters selection + +#ifndef ALICEO2_TPCCLUSSELECTOR_H +#define ALICEO2_TPCCLUSSELECTOR_H + +#include +#include +#include + +namespace o2::tpc +{ +class ClusterNativeAccess; + +class TPCClusSelector +{ + // helper to select TPC cluster matching to certain timebin and optionally pads range + // example of usage: + /* + TPCClusSelector clSel; + o2::tpc::ClusterNativeHelper::Reader tcpClusterReader; + tcpClusterReader.init(native_clusters_file.c_str()); + o2::tpc::ClusterNativeAccess tpcClusterIdxStruct; + std::unique_ptr tpcClusterBuffer; ///< buffer for clusters in tpcClusterIdxStruct + o2::tpc::ClusterNativeHelper::ConstMCLabelContainerViewWithBuffer tpcClusterMCBuffer; ///< buffer for mc labels + + tcpClusterReader.read(iTF); + tcpClusterReader.fillIndex(tpcClusterIdxStruct, tpcClusterBuffer, tpcClusterMCBuffer); + + clSel.fill(tpcClusterIdxStruct); // Create sorted index + // to get i-th cluster in orderer timebins: + const auto& clus = tpcClusterIdxStruct.clusters[sector][row][ clSel.getIndex(sector, row, i)]; + + // to get sorted indices range of clusters in the tbmin:tbmax range + auto rng = clSel.findClustersRange(sector, row, tbmin, tbmax, tpcClusterIdxStruct); + if (rng.first>rng.second) { // nothing is found } + const auto& cln = tpcClusterIdxStruct.clusters[sector][row][clSel.getIndex(sector, row, rng.first )]; /... + + // to get number of clusters in tbmin:tbmax, padmin:padmax range (and optionally get the list) + std::vector cllist; // optional list + int nfnd = clSel.findClustersEntries(sector, row, tbmin, tbmax, padmin, padmax, tpcClusterIdxStruct, &cllist); + for (int i=0;i findClustersRange(int sec, int row, float tbmin, float tbmax, const o2::tpc::ClusterNativeAccess& tpcClusterIdxStruct); + int findClustersEntries(int sec, int row, float tbmin, float tbmax, float padmin, float padmax, const o2::tpc::ClusterNativeAccess& tpcClusterIdxStruct, std::vector* clIDDirect = nullptr); + void fill(const o2::tpc::ClusterNativeAccess& tpcClusterIdxStruct); + + int getNThreads() const { return mNThreads; } + void setNThreads(int n); + + private: + struct Sector { + static constexpr int NRows = 152; + std::array, NRows> rows; + void clear() + { + for (auto& r : rows) + r.clear(); + } + }; + + static constexpr int NSectors = 36; + std::array mSectors{}; + int mNThreads = 1; + + ClassDefNV(TPCClusSelector, 1); +}; + +} // namespace o2::tpc + +#endif diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TPCTrackStudy.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TPCTrackStudy.h index 47385f400ec01..f6396f682ac3b 100644 --- a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TPCTrackStudy.h +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TPCTrackStudy.h @@ -19,15 +19,10 @@ #include "MathUtils/detail/Bracket.h" #include "DataFormatsTPC/ClusterNative.h" -namespace o2::tpc -{ -struct CorrectionMapsLoaderGloOpts; -} - namespace o2::trackstudy { /// create a processor spec -o2::framework::DataProcessorSpec getTPCTrackStudySpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool useMC, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts); +o2::framework::DataProcessorSpec getTPCTrackStudySpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool useMC); } // namespace o2::trackstudy diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackInfoExt.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackInfoExt.h index 935e57873bbd9..e33a0def63842 100644 --- a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackInfoExt.h +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackInfoExt.h @@ -25,6 +25,9 @@ namespace dataformats { struct TrackInfoExt { + enum { TPCA = 0, + TPCC = 1, + kBitMask = 0xffff }; o2::track::TrackParCov track; DCA dca{}; DCA dcaTPC{}; @@ -35,6 +38,7 @@ struct TrackInfoExt { float ttime = 0; float ttimeE = 0; float xmin = 0; + float chi2TPC = 0.f; float chi2ITSTPC = 0.f; float q2ptITS = 0.f; float q2ptTPC = 0.f; @@ -42,12 +46,21 @@ struct TrackInfoExt { float q2ptITSTPCTRD = 0.f; uint16_t nClTPC = 0; uint16_t nClTPCShared = 0; + uint16_t flags = 0; uint8_t pattITS = 0; uint8_t nClITS = 0; uint8_t rowMinTPC = 0; uint8_t padFromEdge = -1; uint8_t rowMaxTPC = 0; uint8_t rowCountTPC = 0; + size_t hashIU = 0; + void setTPCA() { setBit(int(TPCA)); } + void setTPCC() { setBit(int(TPCC)); } + void setTPCAC() { setBit(int(TPCC)); } + + bool isTPCA() const { return isBitSet(int(TPCA)); } + bool isTPCC() const { return isBitSet(int(TPCC)); } + bool isTPCAC() const { return isBitSet(int(TPCA)) && isBitSet(int(TPCC)); } float getTPCInX() const { return innerTPCPos[0]; } float getTPCInY() const { return innerTPCPos[1]; } @@ -56,7 +69,12 @@ struct TrackInfoExt { float getTPCInY0() const { return innerTPCPos0[1]; } float getTPCInZ0() const { return innerTPCPos0[2]; } - ClassDefNV(TrackInfoExt, 5); + void setBits(std::uint16_t b) { flags = b; } + void setBit(int bit) { flags |= kBitMask & (0x1 << bit); } + void resetBit(int bit) { flags &= ~(kBitMask & (0x1 << bit)); } + bool isBitSet(int bit) const { return flags & (kBitMask & (0x1 << bit)); } + + ClassDefNV(TrackInfoExt, 8); }; } // namespace dataformats diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackMCStudy.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackMCStudy.h index d1326a47ac909..18ce3dbf8ab87 100644 --- a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackMCStudy.h +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackMCStudy.h @@ -15,13 +15,12 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" #include "ReconstructionDataFormats/GlobalTrackID.h" -#include "TPCCalibration/CorrectionMapsLoader.h" namespace o2::trackstudy { /// create a processor spec -o2::framework::DataProcessorSpec getTrackMCStudySpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, bool checkSV); +o2::framework::DataProcessorSpec getTrackMCStudySpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool checkSV); } // namespace o2::trackstudy diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackMCStudyConfig.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackMCStudyConfig.h index 7d89928a20b37..ed78ba2a710ec 100644 --- a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackMCStudyConfig.h +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackMCStudyConfig.h @@ -27,9 +27,14 @@ struct TrackMCStudyConfig : o2::conf::ConfigurableParamHelper #include @@ -32,7 +33,8 @@ struct MCTrackInfo { int getNITSClusForAB() const; int getLowestITSLayer() const; int getHighestITSLayer() const; - + std::vector occTPCV{}; + std::vector trackRefsTPC{}; o2::track::TrackPar track{}; o2::MCCompLabel label{}; float occTPC = -1.f; @@ -52,7 +54,28 @@ struct MCTrackInfo { uint8_t maxTPCRowSect = -1; int8_t nITSCl = 0; int8_t pattITSCl = 0; - ClassDefNV(MCTrackInfo, 4); + uint8_t flags = 0; + + enum Flags : uint32_t { Primary = 0, + AddedAtRecStage = 2, + BitMask = 0xff }; + + bool isPrimary() const { return isBitSet(Primary); } + bool isAddedAtRecStage() const { return isBitSet(AddedAtRecStage); } + void setPrimary() { setBit(Primary); } + void setAddedAtRecStage() { setBit(AddedAtRecStage); } + + uint8_t getBits() const { return flags; } + bool isBitSet(int bit) const { return flags & (0xff & (0x1 << bit)); } + void setBits(std::uint8_t b) { flags = b; } + void setBit(int bit) { flags |= BitMask & (0x1 << bit); } + void resetBit(int bit) { flags &= ~(BitMask & (0x1 << bit)); } + + o2::track::TrackPar getTrackParTPC(float b, float x = 90) const; + float getTrackParTPCPar(int i, float b, float x = 90) const; + float getTrackParTPCPhiSec(float b, float x = 90) const; + + ClassDefNV(MCTrackInfo, 8); }; struct RecTrack { @@ -63,6 +86,7 @@ struct RecTrack { FakeTOF = 0x1 << 3, FakeITSTPC = 0x1 << 4, FakeITSTPCTRD = 0x1 << 5, + HASACSides = 0x1 << 6, FakeGLO = 0x1 << 7 }; o2::track::TrackParCov track{}; @@ -70,11 +94,15 @@ struct RecTrack { o2::dataformats::TimeStampWithError ts{}; o2::MCEventLabel pvLabel{}; short pvID = -1; + uint8_t nClTPCShared = 0; uint8_t flags = 0; uint8_t nClITS = 0; uint8_t nClTPC = 0; uint8_t pattITS = 0; int8_t lowestPadRow = -1; + int8_t padFromEdge = -1; + uint8_t rowMaxTPC = 0; + uint8_t rowCountTPC = 0; bool isFakeGLO() const { return flags & FakeGLO; } bool isFakeITS() const { return flags & FakeITS; } @@ -82,8 +110,9 @@ struct RecTrack { bool isFakeTRD() const { return flags & FakeTRD; } bool isFakeTOF() const { return flags & FakeTOF; } bool isFakeITSTPC() const { return flags & FakeITSTPC; } + bool hasACSides() const { return flags & HASACSides; } - ClassDefNV(RecTrack, 1); + ClassDefNV(RecTrack, 3); }; struct TrackPairInfo { @@ -133,6 +162,13 @@ struct TrackFamily { // set of tracks related to the same MC label const RecTrack& getTrackWithTPC() const { return entTPC < 0 ? dummyRecTrack : recTracks[entTPC]; } const RecTrack& getTrackWithITSTPC() const { return entITSTPC < 0 ? dummyRecTrack : recTracks[entITSTPC]; } const RecTrack& getTrackWithITSFound() const { return entITSFound < 0 ? dummyRecTrack : recTracks[entITSFound]; } + const RecTrack& getLongestTPCTrack() const + { + int n = getLongestTPCTrackEntry(); + return n < 0 ? dummyRecTrack : recTracks[n]; + } + int getLongestTPCTrackEntry() const; + int getNTPCClones() const; static RecTrack dummyRecTrack; // ClassDefNV(TrackFamily, 1); @@ -254,6 +290,16 @@ struct ClResTPC { ClassDefNV(ClResTPC, 2); }; +struct ITSHitInfo { + o2::BaseCluster clus{}; + o2::TrackReference tref{}; + float trefXT = 0; // track ref tracking frame coordinates + float trefYT = 0; + float chipX = 0; + float chipAlpha = 0; + ClassDefNV(ITSHitInfo, 1); +}; + struct RecPV { o2::dataformats::PrimaryVertex pv{}; o2::MCEventLabel mcEvLbl{}; @@ -270,7 +316,8 @@ struct MCVertex { int nTrackSel = 0; // number of selected MC charged tracks int ID = -1; std::vector recVtx{}; - ClassDefNV(MCVertex, 1); + std::vector occTPCV{}; + ClassDefNV(MCVertex, 2); }; } // namespace o2::trackstudy diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackingStudy.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackingStudy.h index 7a15c191cbeed..b3a55416f4818 100644 --- a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackingStudy.h +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackingStudy.h @@ -18,12 +18,11 @@ #include "ReconstructionDataFormats/Track.h" #include "MathUtils/detail/Bracket.h" #include "DataFormatsTPC/ClusterNative.h" -#include "TPCCalibration/CorrectionMapsLoader.h" namespace o2::trackstudy { /// create a processor spec -o2::framework::DataProcessorSpec getTrackingStudySpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool useMC, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts); +o2::framework::DataProcessorSpec getTrackingStudySpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool useMC); } // namespace o2::trackstudy diff --git a/Detectors/ITSMFT/ITS/tracking/src/Road.cxx b/Detectors/GlobalTrackingWorkflow/study/src/CheckResidConfig.cxx similarity index 84% rename from Detectors/ITSMFT/ITS/tracking/src/Road.cxx rename to Detectors/GlobalTrackingWorkflow/study/src/CheckResidConfig.cxx index cb6cf47307398..a754d1196017f 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/Road.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/CheckResidConfig.cxx @@ -9,10 +9,6 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "ITStracking/Road.h" -namespace o2 -{ -namespace its -{ -} // namespace its -} // namespace o2 +#include "GlobalTrackingStudy/CheckResidConfig.h" + +O2ParamImpl(o2::checkresid::CheckResidConfig); diff --git a/Detectors/GlobalTrackingWorkflow/study/src/CheckResidSpec.cxx b/Detectors/GlobalTrackingWorkflow/study/src/CheckResidSpec.cxx new file mode 100644 index 0000000000000..6a1915791a911 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/src/CheckResidSpec.cxx @@ -0,0 +1,980 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "GlobalTrackingStudy/CheckResidSpec.h" +#include "GlobalTrackingStudy/CheckResidTypes.h" +#include "GlobalTrackingStudy/CheckResidConfig.h" +#include +#include "ReconstructionDataFormats/Track.h" +#include +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsITSMFT/TrkClusRef.h" +#include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" +#include "ReconstructionDataFormats/TrackTPCITS.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "SimulationDataFormat/MCEventLabel.h" +#include "SimulationDataFormat/MCUtils.h" +#include "CommonUtils/NameConf.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/CCDBParamSpec.h" +#include "Framework/DeviceSpec.h" +#include "DataFormatsITSMFT/DPLAlpideParam.h" +#include "ITSBase/GeometryTGeo.h" +#include "ITStracking/IOUtils.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsBase/GRPGeomHelper.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" +#include "CommonUtils/TreeStreamRedirector.h" +#include "ReconstructionDataFormats/VtxTrackRef.h" +#include "DetectorsVertexing/PVertexer.h" +#include "GlobalTrackingStudy/HistoManager.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef WITH_OPENMP +#include +#endif + +// Attention: in case the residuals are checked with geometry different from the one used for initial reconstruction, +// pass a --configKeyValues option for vertex refit as: +// ;pvertexer.useMeanVertexConstraint=false;pvertexer.meanVertexExtraErrSelection=0.2;pvertexer.iniScale2=100;pvertexer.acceptableScale2=10.; +// In any case, it is better to pass ;pvertexer.useMeanVertexConstraint=false; + +namespace o2::checkresid +{ +using namespace o2::framework; +using DetID = o2::detectors::DetID; +using DataRequest = o2::globaltracking::DataRequest; + +using PVertex = o2::dataformats::PrimaryVertex; +using V2TRef = o2::dataformats::VtxTrackRef; +using VTIndex = o2::dataformats::VtxTrackIndex; +using GTrackID = o2::dataformats::GlobalTrackID; +using timeEst = o2::dataformats::TimeStampWithError; + +class CheckResidSpec : public Task +{ + public: + CheckResidSpec(std::shared_ptr dr, std::shared_ptr gr, GTrackID::mask_t src, bool drawOnly, bool postProcOnly) + : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mDrawOnly(drawOnly), mPostProcOnly(postProcOnly) + { + } + ~CheckResidSpec() final = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(EndOfStreamContext& ec) final; + void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final; + void process(); + + private: + void updateTimeDependentParams(ProcessingContext& pc); + bool refitPV(o2::dataformats::PrimaryVertex& pv, int vid); + bool refitITStrack(o2::track::TrackParCov& track, GTrackID gid); + bool processITSTrack(const o2::its::TrackITS& iTrack, const o2::dataformats::PrimaryVertex& pv, o2::checkresid::Track& resTrack); + void bookHistos(); + void fillHistos(const o2::checkresid::Track& trc); + void postProcessHistos(); + void drawHistos(); + + o2::globaltracking::RecoContainer* mRecoData = nullptr; + int mNThreads = 1; + bool mMeanVertexUpdated = false; + float mITSROFrameLengthMUS = 0.f; + o2::dataformats::MeanVertexObject mMeanVtx{}; + std::vector> mITSClustersArray; ///< ITS clusters created in run() method from compact clusters + const o2::itsmft::TopologyDictionary* mITSDict = nullptr; ///< cluster patterns dictionary + o2::vertexing::PVertexer mVertexer; + std::shared_ptr mDataRequest; + std::shared_ptr mGGCCDBRequest; + std::unique_ptr mDBGOut; + GTrackID::mask_t mTracksSrc{}; + + bool mDrawOnly = false; + bool mPostProcOnly = false; + bool mDraw = false; + bool mFillHistos = true; + bool mFillTree = true; + std::vector> mHManV{}; + o2::HistoManager* mHMan = nullptr; +}; + +void CheckResidSpec::init(InitContext& ic) +{ + mDraw = true; + if (!mDrawOnly) { + mDraw = ic.options().get("draw-report"); + mFillHistos = !ic.options().get("no-hist"); + mFillTree = !ic.options().get("no-tree"); + mNThreads = ic.options().get("nthreads"); + } + const auto& params = o2::checkresid::CheckResidConfig::Instance(); + int lane = ic.services().get().inputTimesliceId; + int maxLanes = ic.services().get().maxInputTimeslices; + std::string nm = params.outname; + if (maxLanes > 1) { + o2::conf::ConfigurableParam::updateFromString(fmt::format("checkresid.outname={}_t{}", nm, lane)); + } + if (mDraw) { + mFillHistos = true; + } + if (!mDrawOnly && mFillHistos) { + bookHistos(); + } + if (!params.ext_hm_list.empty()) { + auto vecNames = o2::utils::Str::tokenize(params.ext_hm_list, ','); + auto vecLegends = o2::utils::Str::tokenize(params.ext_leg_list, ','); + bool useLeg = true; + if (vecNames.size() != vecLegends.size()) { + LOGP(warn, "{} legend names provided for {} external histomanagers, will use file names as legends", vecLegends.size(), vecNames.size()); + useLeg = false; + } + int cntH = 0; + for (const auto& vn : vecNames) { + LOGP(info, "Loading external HistoManager {}", vn); + mHManV.emplace_back() = std::make_unique("", vn, true); + auto hm = mHManV.back().get(); + if (!hm) { + LOGP(error, "Failed to load histograms from {}", vn); + mHManV.pop_back(); + } else { + hm->SetName(useLeg ? vecLegends[cntH].c_str() : vn.c_str()); + } + cntH++; + } + } + if (mDrawOnly) { + return; + } + o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); +#ifndef WITH_OPENMP + if (mNThreads > 1) { + LOGP(warn, "No OpenMP"); + } + mNThreads = 1; +#endif + if (mFillTree) { + mDBGOut = std::make_unique(fmt::format("{}.root", params.outname).c_str(), "recreate"); + } +} + +void CheckResidSpec::run(ProcessingContext& pc) +{ + bool quit = false; + if (mPostProcOnly) { + + postProcessHistos(); + quit = true; + } + if (mDrawOnly) { + drawHistos(); + quit = true; + } + if (quit) { + pc.services().get().endOfStream(); + pc.services().get().readyToQuit(QuitRequest::Me); + return; + } + o2::globaltracking::RecoContainer recoData; + mRecoData = &recoData; + mRecoData->collectData(pc, *mDataRequest.get()); // select tracks of needed type, with minimal cuts, the real selected will be done in the vertexer + mRecoData = &recoData; + updateTimeDependentParams(pc); // Make sure this is called after recoData.collectData, which may load some conditions + process(); + mRecoData = nullptr; +} + +void CheckResidSpec::updateTimeDependentParams(ProcessingContext& pc) +{ + o2::base::GRPGeomHelper::instance().checkUpdates(pc); + pc.inputs().get("meanvtx"); + static bool initOnceDone = false; + if (!initOnceDone) { // this params need to be queried only once + const auto& params = o2::checkresid::CheckResidConfig::Instance(); + initOnceDone = true; + // Note: reading of the ITS AlpideParam needed for ITS timing is done by the RecoContainer + auto grp = o2::base::GRPGeomHelper::instance().getGRPECS(); + const auto& alpParams = o2::itsmft::DPLAlpideParam::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 + } + auto geom = o2::its::GeometryTGeo::Instance(); + geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G, o2::math_utils::TransformType::T2G)); + o2::conf::ConfigurableParam::updateFromString("pvertexer.useTimeInChi2=false;"); + mVertexer.init(); + } + if (mMeanVertexUpdated) { + mMeanVertexUpdated = false; + mVertexer.setMeanVertex(&mMeanVtx); + mVertexer.initMeanVertexConstraint(); + } +} + +void CheckResidSpec::process() +{ + if (!mITSDict) { + LOGP(fatal, "ITS data is not loaded"); + } + const auto itsTracks = mRecoData->getITSTracks(); + // const auto itsLbls = mRecoData->getITSTracksMCLabels(); + const auto itsClRefs = mRecoData->getITSTracksClusterRefs(); + const auto clusITS = mRecoData->getITSClusters(); + const auto patterns = mRecoData->getITSClustersPatterns(); + const auto& params = o2::checkresid::CheckResidConfig::Instance(); + auto pattIt = patterns.begin(); + mITSClustersArray.clear(); + mITSClustersArray.reserve(clusITS.size()); + + o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mITSDict); + + auto pvvec = mRecoData->getPrimaryVertices(); + auto trackIndex = mRecoData->getPrimaryVertexMatchedTracks(); // Global ID's for associated tracks + auto vtxRefs = mRecoData->getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs + auto prop = o2::base::Propagator::Instance(); + static int TFCount = 0; + int nv = vtxRefs.size() - 1; + std::vector> slots; + slots.resize(mNThreads); + int nvGood = 0, nvUse = 0, nvRefFail = 0; + long pvFitDuration{}; + for (int iv = 0; iv < nv; iv++) { + const auto& vtref = vtxRefs[iv]; + auto pve = pvvec[iv]; + if (pve.getNContributors() < params.minPVContributors) { + continue; + } + nvGood++; + if (params.refitPV) { + LOGP(debug, "Refitting PV#{} of {} tracks", iv, pve.getNContributors()); + auto tStartPVF = std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); + bool res = refitPV(pve, iv); + pvFitDuration += std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count() - tStartPVF; + if (!res) { + nvRefFail++; + continue; + } + } + nvUse++; + for (int is = 0; is < GTrackID::NSources; is++) { + if (!mTracksSrc[is] || !mRecoData->isTrackSourceLoaded(is)) { + continue; + } + int idMin = vtref.getFirstEntryOfSource(is), idMax = idMin + vtref.getEntriesOfSource(is); + DetID::mask_t dm = GTrackID::getSourceDetectorsMask(is); + if (!dm[DetID::ITS]) { + continue; + } + if (dm[DetID::TPC] && params.minTPCCl > 0 && !mRecoData->isTrackSourceLoaded(GTrackID::TPC)) { + LOGP(fatal, "Cut on TPC tracks is requested by they are not loaded"); + } +#ifdef WITH_OPENMP +#pragma omp parallel for schedule(dynamic) num_threads(mNThreads) +#endif + for (int i = idMin; i < idMax; i++) { + auto vid = trackIndex[i]; + bool pvCont = vid.isPVContributor(); + if (!pvCont && params.pvcontribOnly) { + continue; + } + if (dm[DetID::TPC] && params.minTPCCl > 0 && mRecoData->getTPCTrack(mRecoData->getTPCContributorGID(vid)).getNClusters() < params.minTPCCl) { + continue; + } + auto gidITS = mRecoData->getITSContributorGID(vid); + if (gidITS.getSource() != GTrackID::ITS) { + continue; + } + const auto& trc = mRecoData->getTrackParam(vid); + const auto& itsTrack = mRecoData->getITSTrack(gidITS); + if (itsTrack.getNClusters() < params.minITSCl) { + continue; + } + auto pt = trc.getPt(); + if (pt < params.minPt || pt > params.maxPt) { + continue; + } + if (std::abs(trc.getTgl()) > params.maxTgl) { + continue; + } + +#ifdef WITH_OPENMP + auto& accum = slots[omp_get_thread_num()]; +#else + auto& accum = slots[0]; +#endif + auto& resTrack = accum.emplace_back(); + resTrack.gid = vid; + if (!processITSTrack(itsTrack, pve, resTrack)) { + accum.pop_back(); + continue; + } + } + } + } + // output + for (const auto& accum : slots) { + for (const auto& tr : accum) { + if (mDBGOut) { + (*mDBGOut) << "res" << "tr=" << tr << "\n"; + } + if (mHMan) { + fillHistos(tr); + } + } + } + LOGP(info, "processed {} PVs out of {} good vertices (out of {} in total), PV refits took {} mus, {} refits failed", nvUse, nvGood, nv, pvFitDuration, nvRefFail); + TFCount++; +} + +bool CheckResidSpec::processITSTrack(const o2::its::TrackITS& iTrack, const o2::dataformats::PrimaryVertex& pv, o2::checkresid::Track& resTrack) +{ + const auto itsClRefs = mRecoData->getITSTracksClusterRefs(); + auto trFitInw = iTrack.getParamOut(); // seed for inward refit + auto trFitOut = iTrack.getParamIn(); // seed for outward refit + auto prop = o2::base::Propagator::Instance(); + auto geom = o2::its::GeometryTGeo::Instance(); + float pvAlpha = 0; + float bz = prop->getNominalBz(); + std::array*, 8> clArr{}; + const auto& params = CheckResidConfig::Instance(); + std::array extrapOut, extrapInw; // 2-way Kalman extrapolations, vertex + 7 layers + + auto rotateTrack = [bz](o2::track::TrackParCov& tr, float alpha, o2::track::TrackPar* refLin) { + return refLin ? tr.rotate(alpha, *refLin, bz) : tr.rotate(alpha); + }; + + auto accountCluster = [&](int i, std::array& extrapDest, o2::track::TrackParCov& tr, o2::track::TrackPar* refLin) { + if (clArr[i]) { // update with cluster + if (!rotateTrack(tr, i == 0 ? pvAlpha : geom->getSensorRefAlpha(clArr[i]->getSensorID()), refLin) || + !prop->propagateTo(tr, refLin, clArr[i]->getX(), true)) { + return 0; + } + extrapDest[i] = tr; // before update + if (!tr.update(*clArr[i])) { + return 0; + } + } else { + extrapDest[i].invalidate(); + return -1; + } + return 1; + }; + + auto inv2d = [](float s00, float s11, float s01) -> std::array { + auto det = s00 * s11 - s01 * s01; + if (det < 1e-16) { + LOGP(error, "Singular det {}, input: {} {} {}", det, s00, s11, s01); + return {0.f, 0.f, 0.f}; + } + det = 1.f / det; + return {s11 * det, s00 * det, -s01 * det}; + }; + + resTrack.points.clear(); + if (!prop->propagateToDCA(pv, trFitOut, bz)) { + LOGP(debug, "Failed to propagateToDCA, {}", trFitOut.asString()); + return false; + } + o2::BaseCluster bcPV; + if (params.addPVAsCluster) { + float cosAlp, sinAlp; + pvAlpha = trFitOut.getAlpha(); + o2::math_utils::sincos(trFitOut.getAlpha(), sinAlp, cosAlp); // vertex position rotated to track frame + bcPV.setXYZ(pv.getX() * cosAlp + pv.getY() * sinAlp, -pv.getX() * sinAlp + pv.getY() * cosAlp, pv.getZ()); + bcPV.setSigmaY2(0.5 * (pv.getSigmaX2() + pv.getSigmaY2())); + bcPV.setSigmaZ2(pv.getSigmaZ2()); + bcPV.setSensorID(-1); + clArr[0] = &bcPV; + } + // collect all track clusters to array, placing them to layer+1 slot + int nCl = iTrack.getNClusters(); + for (int i = 0; i < nCl; i++) { // clusters are ordered from the outermost to the innermost + const auto& curClu = mITSClustersArray[itsClRefs[iTrack.getClusterEntry(i)]]; + + int llr = geom->getLayer(curClu.getSensorID()); + if (clArr[1 + llr]) { + LOGP(error, "Cluster at lr {} was already assigned, old sens {}, new sens {}", llr, clArr[1 + llr]->getSensorID(), curClu.getSensorID()); + } + clArr[1 + geom->getLayer(curClu.getSensorID())] = &curClu; + } + o2::track::TrackPar refLinInw0, refLinOut0, *refLinOut = nullptr, *refLinInw = nullptr; + o2::track::TrackPar refLinIBOut0, refLinOBInw0, *refLinOBInw = nullptr, *refLinIBOut = nullptr; + if (params.useStableRef) { + refLinOut = &(refLinOut0 = trFitOut); + refLinInw = &(refLinInw0 = trFitInw); + } + trFitOut.resetCovariance(); + trFitOut.setCov(trFitOut.getQ2Pt() * trFitOut.getQ2Pt() * trFitOut.getCov()[14], 14); + trFitInw.resetCovariance(); + trFitInw.setCov(trFitInw.getQ2Pt() * trFitInw.getQ2Pt() * trFitInw.getCov()[14], 14); + // fit in inward and outward direction + for (int i = 0; i <= 7; i++) { + int resOut, resInw; + // process resOut in ascending order (0-->7) and resInw in descending order (7-->0) + if (!(resOut = accountCluster(i, extrapOut, trFitOut, refLinOut)) || !(resInw = accountCluster(7 - i, extrapInw, trFitInw, refLinInw))) { + return false; + } + // at layer 3, find the IB track (trIBOut) and the OB track (trOBInw) + // propagate both trcaks to a common radius, RCompIBOB (12cm), and rotates + // them to the same reference frame for comparison + if (i == 3 && resOut == 1 && resInw == 1 && params.doIBOB && nCl == 7) { + resTrack.trIBOut = trFitOut; // outward track updated at outermost IB layer + resTrack.trOBInw = trFitInw; // inward track updated at innermost OB layer + o2::track::TrackPar refLinIBOut0, refLinIBIn0; + if (refLinOut) { + refLinIBOut = &(refLinIBOut0 = refLinOut0); + refLinOBInw = &(refLinOBInw0 = refLinInw0); + } + float xRref; + if (!resTrack.trOBInw.getXatLabR(params.rCompIBOB, xRref, bz) || + !prop->propagateTo(resTrack.trOBInw, refLinOBInw, xRref, true) || + !rotateTrack(resTrack.trOBInw, resTrack.trOBInw.getPhiPos(), refLinOBInw) || // propagate OB track to ref R and rotate + !rotateTrack(resTrack.trIBOut, resTrack.trOBInw.getAlpha(), refLinIBOut) || + !prop->propagateTo(resTrack.trIBOut, refLinIBOut, resTrack.trOBInw.getX(), true)) { // rotate OB track to same frame and propagate to same X + // if any propagation or rotation steps fail, invalidate both tracks + return false; + } + } + } + + bool innerDone = false; + if (params.doResid) { + for (int i = 0; i <= 7; i++) { + if (clArr[i]) { + // calculate interpolation as a weighted mean of inward/outward extrapolations to this layer + const auto &tInw = extrapInw[i], &tOut = extrapOut[i]; + auto wInw = inv2d(tInw.getSigmaY2(), tInw.getSigmaZ2(), tInw.getSigmaZY()); + auto wOut = inv2d(tOut.getSigmaY2(), tOut.getSigmaZ2(), tOut.getSigmaZY()); + if (wInw[0] == 0.f || wOut[0] == 0.f) { + return false; + } + std::array wTot = {wInw[0] + wOut[0], wInw[1] + wOut[1], wInw[2] + wOut[2]}; + auto cTot = inv2d(wTot[0], wTot[1], wTot[2]); + auto ywi = wInw[0] * tInw.getY() + wInw[2] * tInw.getZ() + wOut[0] * tOut.getY() + wOut[2] * tOut.getZ(); + auto zwi = wInw[2] * tInw.getY() + wInw[1] * tInw.getZ() + wOut[2] * tOut.getY() + wOut[1] * tOut.getZ(); + auto yw = ywi * cTot[0] + zwi * cTot[2]; + auto zw = ywi * cTot[2] + zwi * cTot[1]; + // posCl.push_back(clArr[i]->getXYZGlo(*o2::its::GeometryTGeo::Instance())); + auto phi = i == 0 ? tInw.getPhi() : tInw.getPhiPos(); + o2::math_utils::bringTo02Pi(phi); + resTrack.points.emplace_back(clArr[i]->getY() - yw, clArr[i]->getZ() - zw, cTot[0] + clArr[i]->getSigmaY2(), cTot[1] + clArr[i]->getSigmaZ2(), phi, clArr[i]->getZ(), clArr[i]->getSensorID(), i - 1); + if (!innerDone) { + resTrack.track = tInw; + innerDone = true; + } + } else { + LOGP(debug, "No cluster on lr {}", i); + } + } + } + return true; +} + +bool CheckResidSpec::refitPV(o2::dataformats::PrimaryVertex& pv, int vid) +{ + const auto& params = o2::checkresid::CheckResidConfig::Instance(); + std::vector tracks; + std::vector useTrack; + std::vector gidsITS; + int ntr = pv.getNContributors(), ntrIni = ntr; + tracks.reserve(ntr); + useTrack.reserve(ntr); + gidsITS.reserve(ntr); + const auto& vtref = mRecoData->getPrimaryVertexMatchedTrackRefs()[vid]; + auto trackIndex = mRecoData->getPrimaryVertexMatchedTracks(); + int itr = vtref.getFirstEntry(), itLim = itr + vtref.getEntries(); + for (; itr < itLim; itr++) { + auto tid = trackIndex[itr]; + if (tid.isPVContributor() && mRecoData->isTrackSourceLoaded(tid.getSource())) { + tracks.emplace_back().setPID(mRecoData->getTrackParam(tid).getPID()); + gidsITS.push_back(mRecoData->getITSContributorGID(tid)); + } + } + ntr = tracks.size(); + useTrack.resize(ntr); +#ifdef WITH_OPENMP +#pragma omp parallel for schedule(dynamic) num_threads(mNThreads) +#endif + for (int itr = 0; itr < ntr; itr++) { + if (!(useTrack[itr] = refitITStrack(tracks[itr], gidsITS[itr]))) { + tracks[itr] = mRecoData->getTrackParam(gidsITS[itr]); // this track will not be used but participates in prepareVertexRefit + } + } + ntr = 0; + for (auto v : useTrack) { + ntr++; + } + if (ntr < params.minPVContributors || !mVertexer.prepareVertexRefit(tracks, pv)) { + LOGP(warn, "Abandon vertex refit: NcontribNew = {} vs NcontribOld = {}", ntr, ntrIni); + return false; + } + LOGP(debug, "Original vtx: Nc:{} {}, chi2={}", pv.getNContributors(), pv.asString(), pv.getChi2()); + auto pvSave = pv; + pv = mVertexer.refitVertexFull(useTrack, pv); + LOGP(debug, "Refitted vtx: Nc:{} {}, chi2={}", ntr, pv.asString(), pv.getChi2()); + if (pv.getChi2() < 0.f) { + LOGP(warn, "Failed to refit PV {}", pvSave.asString()); + return false; + } + return true; +} + +bool CheckResidSpec::refitITStrack(o2::track::TrackParCov& track, GTrackID gid) +{ + // destination tack might have non-default PID assigned + const auto& trkITS = mRecoData->getITSTrack(gid); + const auto itsClRefs = mRecoData->getITSTracksClusterRefs(); + const auto& params = CheckResidConfig::Instance(); + auto pid = track.getPID(); + track = trkITS.getParamOut(); + track.resetCovariance(); + track.setCov(track.getQ2Pt() * track.getQ2Pt() * track.getCov()[14], 14); + track.setPID(pid); + auto nCl = trkITS.getNumberOfClusters(); + auto geom = o2::its::GeometryTGeo::Instance(); + auto prop = o2::base::Propagator::Instance(); + float bz = prop->getNominalBz(); + o2::track::TrackPar refLin{track}; + + for (int iCl = 0; iCl < nCl; iCl++) { // clusters are stored from outer to inner layers + const auto& cls = mITSClustersArray[itsClRefs[trkITS.getClusterEntry(iCl)]]; + auto alpha = geom->getSensorRefAlpha(cls.getSensorID()); + if (!(params.useStableRef ? track.rotate(alpha, refLin, bz) : track.rotate(alpha)) || + !prop->propagateTo(track, params.useStableRef ? &refLin : nullptr, cls.getX(), true)) { + LOGP(debug, "refitITStrack failed on propagation to cl#{}, alpha={}, x={} | {}", iCl, alpha, cls.getX(), track.asString()); + return false; + } + if (!track.update(cls)) { + LOGP(debug, "refitITStrack failed on update with cl#{}, | {}", iCl, track.asString()); + return false; + } + } + return true; +} + +void CheckResidSpec::fillHistos(const o2::checkresid::Track& trc) +{ + const auto& params = CheckResidConfig::Instance(); + int np = trc.points.size(); + auto pt = trc.track.getPt(); + if (pt < params.minPt || pt > params.maxPt) { + return; + } + for (int ip = 0; ip < np; ip++) { + const auto& pnt = trc.points[ip]; + int il = pnt.lr >= 0 ? pnt.lr + 1 : 0; + mHMan->getHisto2F(il * 10 + 0 * 100)->Fill(pnt.phi, pnt.dy); + mHMan->getHisto2F(il * 10 + 0 * 100 + 1000)->Fill(pnt.z, pnt.dy); + mHMan->getHisto2F(il * 10 + 0 * 100 + 2000)->Fill(pt, pnt.dy); + mHMan->getHisto2F(il * 10 + 0 * 100 + 3000)->Fill(trc.track.getTgl(), pnt.dy); + if (pnt.sig2y > 0) { + auto pull = pnt.dy / std::sqrt(pnt.sig2y); + mHMan->getHisto2F(il * 10 + 0 * 100 + 5)->Fill(pnt.phi, pull); + mHMan->getHisto2F(il * 10 + 0 * 100 + 5 + 1000)->Fill(pnt.z, pull); + mHMan->getHisto2F(il * 10 + 0 * 100 + 5 + 2000)->Fill(pt, pull); + mHMan->getHisto2F(il * 10 + 0 * 100 + 5 + 3000)->Fill(trc.track.getTgl(), pull); + } + mHMan->getHisto2F(il * 10 + 1 * 100)->Fill(pnt.phi, pnt.dz); + mHMan->getHisto2F(il * 10 + 1 * 100 + 1000)->Fill(pnt.z, pnt.dz); + mHMan->getHisto2F(il * 10 + 1 * 100 + 2000)->Fill(pt, pnt.dz); + mHMan->getHisto2F(il * 10 + 1 * 100 + 3000)->Fill(trc.track.getTgl(), pnt.dz); + if (pnt.sig2z > 0) { + auto pull = pnt.dz / std::sqrt(pnt.sig2z); + mHMan->getHisto2F(il * 10 + 1 * 100 + 5)->Fill(pnt.phi, pull); + mHMan->getHisto2F(il * 10 + 1 * 100 + 5 + 1000)->Fill(pnt.z, pull); + mHMan->getHisto2F(il * 10 + 1 * 100 + 5 + 2000)->Fill(pt, pull); + mHMan->getHisto2F(il * 10 + 1 * 100 + 5 + 3000)->Fill(trc.track.getTgl(), pull); + } + } + //-------------- + if (trc.trIBOut.getX() > 1 && std::abs(trc.trIBOut.getX() - trc.trOBInw.getX()) < 0.1) { + for (int ip = 0; ip < 5; ip++) { + float d = trc.trIBOut.getParam(ip) - trc.trOBInw.getParam(ip); + mHMan->getHisto2F(10000 + ip * 10)->Fill(trc.trIBOut.getPhiPos(), d); + mHMan->getHisto2F(11000 + ip * 10)->Fill(trc.trIBOut.getZ(), d); + mHMan->getHisto2F(12000 + ip * 10)->Fill(pt, d); + mHMan->getHisto2F(13000 + ip * 10)->Fill(trc.track.getTgl(), d); + float sg = trc.trIBOut.getCovarElem(ip, ip) + trc.trOBInw.getCovarElem(ip, ip); + if (sg > 0) { + auto pull = d / std::sqrt(sg); + mHMan->getHisto2F(10000 + ip * 10 + 5)->Fill(trc.trIBOut.getPhiPos(), pull); + mHMan->getHisto2F(11000 + ip * 10 + 5)->Fill(trc.trIBOut.getZ(), pull); + mHMan->getHisto2F(12000 + ip * 10 + 5)->Fill(pt, pull); + mHMan->getHisto2F(13000 + ip * 10 + 5)->Fill(trc.track.getTgl(), pull); + } + } + } +} + +void CheckResidSpec::bookHistos() +{ + const auto& params = o2::checkresid::CheckResidConfig::Instance(); + mHManV.emplace_back() = std::make_unique("", fmt::format("{}_hman.root", params.outname)); + mHMan = mHManV.back().get(); + mHMan->SetName(params.outname.c_str()); + auto defLogAxis = [](float xMn, float xMx, int nbin) { // get array for log axis + if (xMn <= 0 || xMx <= xMn || nbin < 2) { + LOGP(fatal, "Wrong log axis request: xmin = {} xmax = {} nbins = {}", xMn, xMx, nbin); + } + auto dx = std::log(xMx / xMn) / nbin; + std::vector xax(nbin + 1); + for (int i = 0; i <= nbin; i++) { + xax[i] = xMn * std::exp(dx * i); + } + return xax; + }; + float minPt = std::max(0.1f, params.minPt), maxPt = std::min(50.f, params.maxPt); + auto ptax = defLogAxis(minPt, maxPt, params.nBinsPt); + + for (int il = 0; il < 8; il++) { + std::string lrName = il == 0 ? "Vtx" : fmt::format("Lr{}", il - 1); + for (int iyz = 0; iyz < 2; iyz++) { + std::string dname = iyz == 0 ? "dy" : "dz", dtit = iyz == 0 ? "#DeltaY" : "#DeltaZ"; + auto h2 = new TH2F(fmt::format("{}_{}_{}", dname, lrName, "phi").c_str(), fmt::format("{}_{{{}}} vs {};#phi;{}", dtit, lrName, "#phi", dtit).c_str(), params.nBinsPhi, 0, TMath::Pi() * 2, params.nBinsRes, -params.maxDYZ[il], params.maxDYZ[il]); + mHMan->addHisto(h2, il * 10 + iyz * 100); + auto h2p = new TH2F(fmt::format("{}_{}_{}_pull", dname, lrName, "phi").c_str(), fmt::format("pull {}_{{{}}} vs {};#phi; pull{}", dtit, lrName, "phi", dtit).c_str(), params.nBinsPhi, 0, TMath::Pi() * 2, params.nBinsRes, -params.maxPull, params.maxPull); + mHMan->addHisto(h2p, il * 10 + iyz * 100 + 5); + + auto hz2 = new TH2F(fmt::format("{}_{}_{}", dname, lrName, "Z").c_str(), fmt::format("{}_{{{}}} vs {};Z;{}", dtit, lrName, "Z", dtit).c_str(), params.nBinsZ, -params.zranges[il], params.zranges[il], params.nBinsRes, -params.maxDYZ[il], params.maxDYZ[il]); + mHMan->addHisto(hz2, il * 10 + iyz * 100 + 1000); + auto hz2p = new TH2F(fmt::format("{}_{}_{}_pull", dname, lrName, "Z").c_str(), fmt::format("pull {}_{{{}}} vs {};Z; pull{}", dtit, lrName, "Z", dtit).c_str(), params.nBinsZ, -params.zranges[il], params.zranges[il], params.nBinsRes, -params.maxPull, params.maxPull); + mHMan->addHisto(hz2p, il * 10 + iyz * 100 + 5 + 1000); + + auto hpt2 = new TH2F(fmt::format("{}_{}_{}", dname, lrName, "Pt").c_str(), fmt::format("{}_{{{}}} vs {};p_{{T}};{}", dtit, lrName, "p_{T}", dtit).c_str(), params.nBinsPt, ptax.data(), params.nBinsRes, -params.maxDYZ[il], params.maxDYZ[il]); + mHMan->addHisto(hpt2, il * 10 + iyz * 100 + 2000); + auto hpt2p = new TH2F(fmt::format("{}_{}_{}_pull", dname, lrName, "Pt").c_str(), fmt::format("pull {}_{{{}}} vs {};p_{{T}}; pull{}", dtit, lrName, "p_{T}", dtit).c_str(), params.nBinsPt, ptax.data(), params.nBinsRes, -params.maxPull, params.maxPull); + mHMan->addHisto(hpt2p, il * 10 + iyz * 100 + 5 + 2000); + + auto htgl2 = new TH2F(fmt::format("{}_{}_{}", dname, lrName, "tgl").c_str(), fmt::format("{}_{{{}}} vs {};tg#lambda;{}", dtit, lrName, "tg#lambda", dtit).c_str(), params.nBinsTgl, -params.maxTgl, params.maxTgl, params.nBinsRes, -params.maxDYZ[il], params.maxDYZ[il]); + mHMan->addHisto(htgl2, il * 10 + iyz * 100 + 3000); + auto htgl2p = new TH2F(fmt::format("{}_{}_{}_pull", dname, lrName, "tgl").c_str(), fmt::format("pull {}_{{{}}} vs {};tg#lambda; pull{}", dtit, lrName, "tg#lambda", dtit).c_str(), params.nBinsTgl, -params.maxTgl, params.maxTgl, params.nBinsRes, -params.maxPull, params.maxPull); + mHMan->addHisto(htgl2p, il * 10 + iyz * 100 + 5 + 3000); + } + } + + for (int ip = 0; ip < 5; ip++) { + auto h2 = new TH2F(fmt::format("dPar{}_IBOBphi", ip).c_str(), fmt::format("#Delta par{} IB-OB vs phi;#phi;#Delta par{}", ip, ip).c_str(), params.nBinsPhi, 0, TMath::Pi() * 2, params.nBinsRes, -params.maxDPar[ip], params.maxDPar[ip]); + mHMan->addHisto(h2, 10000 + ip * 10); + auto h2p = new TH2F(fmt::format("dPar{}_IBOBphi_pull", ip).c_str(), fmt::format("pull #Delta par{} IB-OB vs phi;#phi;pull #Delta par{}", ip, ip).c_str(), params.nBinsPhi, 0, TMath::Pi() * 2, params.nBinsRes, -params.maxPull, params.maxPull); + mHMan->addHisto(h2p, 10000 + ip * 10 + 5); + + auto hz2 = new TH2F(fmt::format("dPar{}_IBOBz", ip).c_str(), fmt::format("#Delta par{} IB-OB vs Z;Z;#Delta par{}", ip, ip).c_str(), params.nBinsZ, -20., 20., params.nBinsRes, -params.maxDPar[ip], params.maxDPar[ip]); + mHMan->addHisto(hz2, 11000 + ip * 10); + auto hz2p = new TH2F(fmt::format("dPar{}_IBOBz_pull", ip).c_str(), fmt::format("pull #Delta par{} IB-OB vs Z;Z;pull #Delta par{}", ip, ip).c_str(), params.nBinsZ, -20., 20., params.nBinsRes, -params.maxPull, params.maxPull); + mHMan->addHisto(hz2p, 11000 + ip * 10 + 5); + + auto hpt2 = new TH2F(fmt::format("dPar{}_IBOBpt", ip).c_str(), fmt::format("#Delta par{} IB-OB vs pT;p_{{T}};#Delta par{}", ip, ip).c_str(), params.nBinsPt, ptax.data(), params.nBinsRes, -params.maxDPar[ip], params.maxDPar[ip]); + mHMan->addHisto(hpt2, 12000 + ip * 10); + auto hpt2p = new TH2F(fmt::format("dPar{}_IBOBpt_pull", ip).c_str(), fmt::format("pull #Delta par{} IB-OB vs pT;p_{{T}};pull #Delta par{}", ip, ip).c_str(), params.nBinsPt, ptax.data(), params.nBinsRes, -params.maxPull, params.maxPull); + mHMan->addHisto(hpt2p, 12000 + ip * 10 + 5); + + auto htgl2 = new TH2F(fmt::format("dPar{}_IBOBtgl", ip).c_str(), fmt::format("#Delta par{} IB-OB vs tg#lambda;tg#lambda;#Delta par{}", ip, ip).c_str(), params.nBinsTgl, -params.maxTgl, params.maxTgl, params.nBinsRes, -params.maxDPar[ip], params.maxDPar[ip]); + mHMan->addHisto(htgl2, 13000 + ip * 10); + auto htgl2p = new TH2F(fmt::format("dPar{}_IBOBtgl_pull", ip).c_str(), fmt::format("pull #Delta par{} IB-OB vs tg#lambda;tg#lambda;pull #Delta par{}", ip, ip).c_str(), params.nBinsTgl, -params.maxTgl, params.maxTgl, params.nBinsRes, -params.maxPull, params.maxPull); + mHMan->addHisto(htgl2p, 13000 + ip * 10 + 5); + } +} + +void CheckResidSpec::postProcessHistos() +{ + printf("Fitting histos\n"); + if (!mHMan) { + if (mHManV.empty()) { + LOGP(warn, "nothing to process"); + return; + } + mHMan = mHManV[0].get(); + } + const auto& params = o2::checkresid::CheckResidConfig::Instance(); + auto gs = new TF1("gs", "gaus", -1, 1); + int maxH = mPostProcOnly ? mHManV.size() : 1; + TObjArray arr; + for (int ihm = 0; ihm < maxH; ihm++) { + auto* histm = mHManV[ihm].get(); + auto fitSlices = [&](int id) { + auto h2 = histm->getHisto2F(id); + if (!h2 || h2->GetEntries() < params.minHistoStat2Fit) { + return; + } + h2->FitSlicesY(gs, 0, -1, 0, "QNR", &arr); + arr.SetOwner(true); + TH1* hmean = (TH1*)arr.RemoveAt(1); + if (hmean) { + hmean->SetTitle(Form("<%s>", h2->GetTitle())); + histm->addHisto(hmean, id + 1); + } + TH1* hsig = (TH1*)arr.RemoveAt(2); + if (hsig) { + hsig->SetTitle(Form("#sigma(%s)", h2->GetTitle())); + histm->addHisto(hsig, id + 2); + } + }; + for (int ioffs = 0; ioffs <= 3; ioffs++) { // vs phi, Z, pT, tgl + int offs = ioffs * 1000; + for (int iht = 0; iht < 2; iht++) { // resid, pull + int offsV = iht == 0 ? 0 : 5; + for (int il = 0; il < 8; il++) { + for (int iyz = 0; iyz < 2; iyz++) { + fitSlices(il * 10 + iyz * 100 + offsV + offs); + } + } + for (int ip = 0; ip < 5; ip++) { + fitSlices(10000 + ip * 10 + offsV + offs); + } + } + } + histm->write(); + } + delete gs; +} + +void CheckResidSpec::drawHistos() +{ + gROOT->SetBatch(true); + gStyle->SetTitleX(0.2); + gStyle->SetTitleY(0.88); + gStyle->SetTitleW(0.25); + gStyle->SetOptStat(0); + int nhm = mHManV.size(); + std::array hcol{EColor::kRed, EColor::kBlue, EColor::kGreen + 2}; + std::unique_ptr lg; + lg = std::make_unique(0.12, 0.13, 0.9, 0.13 + std::min(0.5f, nhm * 0.2f / 3.f)); + lg->SetFillStyle(0); + lg->SetBorderSize(0); + for (int i = 0; i < nhm; i++) { + auto hman = mHManV[i].get(); + if (!hman || hman->GetLast() < 1) { + continue; + } + hman->setMarkerStyle(20 + i + (i % 2) * 4, 0.5); + hman->setColor(hcol[i % hcol.size()]); + auto le = lg->AddEntry(hman->getHisto(1), hman->GetName(), "lp"); + le->SetTextColor(hcol[i % hcol.size()]); + } + TCanvas cly("cly", "", 600, 800), clz("clz", "", 600, 800), clpar("clpar", "", 600, 800); + TCanvas czly("czly", "", 600, 800), czlz("czlz", "", 600, 800), czlpar("czlpar", "", 600, 800); + const auto& params = o2::checkresid::CheckResidConfig::Instance(); + + auto AddLabel = [](const char* txt, float x = 0.1, float y = 0.9, int color = kBlack, float size = 0.04) { + TLatex* lt = new TLatex(x, y, txt); + lt->SetNDC(); + lt->SetTextColor(color); + lt->SetTextSize(size); + lt->Draw(); + return lt; + }; + + auto drawResLr = [this](TCanvas& canv, int offs, const float resMM[8], bool logX) { + canv.Clear(); + canv.Divide(2, 4); + int nh = this->mHManV.size(); + for (int i = 0; i < 8; i++) { + canv.cd(i + 1); + bool same = false; + for (int j = 0; j < nh; j++) { + auto hman = this->mHManV[j].get(); + if (!hman || hman->GetLast() < 1) { + continue; + } + if (auto histo = hman->getHisto(10 * i + offs)) { + histo->Draw(same ? "same" : ""); + if (!same) { + histo->SetMinimum(-resMM[i]); + histo->SetMaximum(resMM[i]); + same = true; + } + } + } + gPad->SetGrid(); + gPad->SetLogx(logX); + } + }; + + auto drawResPar = [this](TCanvas& canv, int offs, const float resMM[8], bool logX) { + canv.Clear(); + canv.Divide(2, 3); + int nh = this->mHManV.size(); + for (int i = 0; i < 5; i++) { + canv.cd(i + 1); + bool same = false; + for (int j = 0; j < nh; j++) { + auto hman = this->mHManV[j].get(); + if (!hman || hman->GetLast() < 1) { + continue; + } + if (auto histo = hman->getHisto(10 * i + offs)) { + histo->Draw(same ? "same" : ""); + if (!same) { + histo->SetMinimum(-resMM[i]); + histo->SetMaximum(resMM[i]); + same = true; + } + } + } + gPad->SetGrid(); + gPad->SetLogx(logX); + } + }; + + cly.Print(Form("%s_hman.pdf[", params.outname.c_str())); + drawResLr(cly, 1, params.resMMLrY, false); + cly.cd(2); + lg->Draw(); + AddLabel("Y residuals", 0.1, 0.95); + cly.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResLr(clz, 101, params.resMMLrZ, false); + clz.cd(2); + lg->Draw(); + AddLabel("Z residuals", 0.1, 0.95); + clz.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResLr(czly, 1001, params.resMMLrY, false); + czly.cd(2); + lg->Draw(); + AddLabel("Y residuals", 0.1, 0.95); + czly.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResLr(czlz, 1101, params.resMMLrZ, false); + czlz.cd(2); + lg->Draw(); + AddLabel("Z residuals", 0.1, 0.95); + czlz.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResLr(czly, 2001, params.resMMLrY, true); + czly.cd(2); + lg->Draw(); + AddLabel("Y residuals", 0.1, 0.95); + czly.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResLr(czlz, 2101, params.resMMLrZ, true); + czlz.cd(2); + lg->Draw(); + AddLabel("Z residuals", 0.1, 0.95); + czlz.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResLr(czly, 3001, params.resMMLrY, false); + czly.cd(2); + lg->Draw(); + AddLabel("Y residuals", 0.1, 0.95); + czly.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResLr(czlz, 3101, params.resMMLrZ, false); + czlz.cd(2); + lg->Draw(); + AddLabel("Z residuals", 0.1, 0.95); + czlz.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResPar(clpar, 10001, params.resMMPar, false); + clpar.cd(6); + lg->Draw(); + AddLabel("IB-OB tracks params differences at R = 12 cm", 0.2, 0.8); + clpar.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResPar(czlpar, 11001, params.resMMPar, false); + czlpar.cd(6); + lg->Draw(); + AddLabel("IB-OB tracks params differences at R = 12 cm", 0.2, 0.8); + czlpar.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResPar(czlpar, 12001, params.resMMPar, true); + czlpar.cd(6); + lg->Draw(); + AddLabel("IB-OB tracks params differences at R = 12 cm", 0.2, 0.8); + czlpar.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResPar(czlpar, 13001, params.resMMPar, false); + czlpar.cd(6); + lg->Draw(); + AddLabel("IB-OB tracks params differences at R = 12 cm", 0.2, 0.8); + czlpar.Print(Form("%s_hman.pdf", params.outname.c_str())); + + cly.Print(Form("%s_hman.pdf]", params.outname.c_str())); +} + +void CheckResidSpec::endOfStream(EndOfStreamContext& ec) +{ + mDBGOut.reset(); + if (mHManV.size()) { + postProcessHistos(); + } + if (mDraw) { + drawHistos(); + } +} + +void CheckResidSpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) +{ + if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { + return; + } + if (matcher == ConcreteDataMatcher("GLO", "MEANVERTEX", 0)) { + LOG(info) << "Imposing new MeanVertex: " << ((const o2::dataformats::MeanVertexObject*)obj)->asString(); + mMeanVtx = *(const o2::dataformats::MeanVertexObject*)obj; + mMeanVertexUpdated = true; + return; + } + if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) { + LOG(info) << "cluster dictionary updated"; + mITSDict = (const o2::itsmft::TopologyDictionary*)obj; + return; + } +} + +DataProcessorSpec getCheckResidSpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool drawOnly, bool postProcOnly) +{ + std::vector outputs; + auto dataRequest = std::make_shared(); + if (!drawOnly && !postProcOnly) { + bool useMC = false; + dataRequest->requestTracks(srcTracks, useMC); + dataRequest->requestClusters(srcClusters, useMC); + dataRequest->requestPrimaryVertices(useMC); + dataRequest->inputs.emplace_back("meanvtx", "GLO", "MEANVERTEX", 0, Lifetime::Condition, ccdbParamSpec("GLO/Calib/MeanVertex", {}, 1)); + } + auto ggRequest = drawOnly ? std::make_shared(false, false, false, false, false, o2::base::GRPGeomRequest::None, dataRequest->inputs) : std::make_shared(false, // orbitResetTime + true, // GRPECS=true + true, // GRPLHCIF + true, // GRPMagField + true, // askMatLUT + o2::base::GRPGeomRequest::Aligned, // geometry + dataRequest->inputs, true); + Options opts; + if (!drawOnly) { + opts = Options{ + {"nthreads", VariantType::Int, 1, {"number of threads"}}, + {"no-tree", VariantType::Bool, false, {"do not fill residuals tree"}}, + {"no-hist", VariantType::Bool, false, {"do not fill residuals histograms"}}, + {"draw-report", VariantType::Bool, false, {"fill residuals report"}}, + }; + } + + return DataProcessorSpec{ + "check-resid", + dataRequest->inputs, + outputs, + AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, srcTracks, drawOnly, postProcOnly)}, + opts}; +} + +} // namespace o2::checkresid diff --git a/Detectors/GlobalTrackingWorkflow/study/src/DumpTracks.cxx b/Detectors/GlobalTrackingWorkflow/study/src/DumpTracks.cxx index dbf34b8eb14ad..8c7931d599e93 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/DumpTracks.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/DumpTracks.cxx @@ -21,7 +21,7 @@ #include "Framework/ConfigParamRegistry.h" #include "Framework/CCDBParamSpec.h" #include "FT0Reconstruction/InteractionTag.h" -#include "ITSMFTBase/DPLAlpideParam.h" +#include "DataFormatsITSMFT/DPLAlpideParam.h" #include "DetectorsCommonDataFormats/DetID.h" #include "DetectorsBase/GRPGeomHelper.h" #include "GlobalTrackingStudy/TrackingStudy.h" @@ -48,7 +48,7 @@ using TBracket = o2::math_utils::Bracketf_t; using timeEst = o2::dataformats::TimeStampWithError; -class DumpTracksSpec : public Task +class DumpTracksSpec final : public Task { public: DumpTracksSpec(std::shared_ptr dr, std::shared_ptr gr, GTrackID::mask_t src, bool useMC) diff --git a/Detectors/GlobalTrackingWorkflow/study/src/GlobalTrackingStudyLinkDef.h b/Detectors/GlobalTrackingWorkflow/study/src/GlobalTrackingStudyLinkDef.h index f666132c9c1cf..b1fe732fbefc4 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/GlobalTrackingStudyLinkDef.h +++ b/Detectors/GlobalTrackingWorkflow/study/src/GlobalTrackingStudyLinkDef.h @@ -38,5 +38,17 @@ #pragma link C++ class std::vector < o2::trackstudy::ClResTPCCont> + ; #pragma link C++ class o2::trackstudy::TrackPairInfo + ; #pragma link C++ class std::vector < o2::trackstudy::TrackPairInfo> + ; +#pragma ling C++ class o2::tpc::TPCClusSelector + ; + +#pragma link C++ class o2::trackstudy::ITSHitInfo + ; +#pragma link C++ class std::vector < o2::trackstudy::ITSHitInfo> + ; + +#pragma link C++ class o2::checkresid::Point + ; +#pragma link C++ class std::vector < o2::checkresid::Point> + ; +#pragma link C++ class o2::checkresid::Track + ; +#pragma link C++ class o2::checkresid::CheckResidConfig + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::checkresid::CheckResidConfig> + ; + +#pragma link C++ class o2::HistoManager + ; #endif diff --git a/Detectors/GlobalTrackingWorkflow/study/src/HistoManager.cxx b/Detectors/GlobalTrackingWorkflow/study/src/HistoManager.cxx new file mode 100644 index 0000000000000..e57a78e4b202d --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/src/HistoManager.cxx @@ -0,0 +1,505 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Framework/Logger.h" +#include "GlobalTrackingStudy/HistoManager.h" + +namespace o2 +{ + +HistoManager::HistoManager(const std::string& dirname, const std::string& fname, bool load, const std::string& prefix) : mDirName(dirname) +{ + setFileName(fname); + if (load && !mDefName.empty()) { + int nh = this->load(fname, dirname); + LOGP(info, "HistoManager::load was requested: got {} histos from {}/{}", nh, fname, dirname); + if (!prefix.empty()) { + addPrefix(prefix); + } + } +} + +HistoManager* HistoManager::createClone(const std::string& prefix) const +{ + auto* hm = static_cast(Clone()); + hm->addPrefix(prefix); + for (int i = 0; i < GetLast() + 1; ++i) { + TObject* obj = hm->UncheckedAt(i); + if (!obj) { + continue; + } + if (auto* histo = dynamic_cast(obj)) { + histo->SetDirectory(nullptr); + } + } + hm->mNHistos = mNHistos; + hm->setFileName(mDefName); + hm->setDirName(mDirName); + return hm; +} + +int HistoManager::addHisto(TH1* histo, int at) +{ + if (!histo) { + return mNHistos; + } + if (at < 0) { + at = mNHistos; + } + AddAtAndExpand(histo, at); + histo->SetDirectory(nullptr); + histo->SetUniqueID(at + 1); + return mNHistos++; +} + +TGraph* HistoManager::getGraph(int id) const +{ + return id <= GetLast() ? dynamic_cast(UncheckedAt(id)) : nullptr; +} + +TH1* HistoManager::getHisto(int id) const +{ + return id <= GetLast() ? dynamic_cast(UncheckedAt(id)) : nullptr; +} + +TH1* HistoManager::getHisto(const std::string& name) const +{ + return dynamic_cast(FindObject(name.c_str())); +} + +TH1F* HistoManager::getHisto1F(int id) const +{ + return dynamic_cast(UncheckedAt(id)); +} + +TH2F* HistoManager::getHisto2F(int id) const +{ + return dynamic_cast(UncheckedAt(id)); +} + +TProfile* HistoManager::getHistoP(int id) const +{ + return dynamic_cast(UncheckedAt(id)); +} + +int HistoManager::addGraph(TGraph* gr, int at) +{ + if (!gr) { + return mNHistos; + } + if (at < 0) { + at = mNHistos; + } + AddAtAndExpand(gr, at); + gr->SetUniqueID(at + 1); + return mNHistos++; +} + +void HistoManager::Compress() +{ + TObjArray::Compress(); + for (int i = 0; i < GetLast() + 1; ++i) { + if (TObject* histo = At(i)) { + histo->SetUniqueID(i + 1); + } + } +} + +void HistoManager::write(TFile* file) +{ + if (!mNHistos) { + return; + } + + bool localFile = kFALSE; + TFile* lfile = nullptr; + const char* dirName = nullptr; + if (file) { + lfile = file; + } else { + auto* tmpF = static_cast(gROOT->GetListOfFiles()->FindObject(mDefName.c_str())); + if (tmpF && tmpF->IsOpen()) { + TString opt = tmpF->GetOption(); + opt.ToLower(); + if (!opt.Contains("read")) { + lfile = tmpF; + tmpF->cd(); + } + } + } + + TString pwd = gDirectory->GetPath(); + if (!lfile) { + std::string originalName = mDefName; + if (mDefName.empty() || mDefName[0] == ' ') { + mDefName = "histoman"; + } + TString rootName = mDefName.c_str(); + if (!rootName.Contains(".root")) { + mDefName += ".root"; + } + lfile = TFile::Open(mDefName.c_str(), "UPDATE"); + mDefName = originalName; + localFile = kTRUE; + } + + lfile->cd(); + dirName = mDirName.c_str(); + if (dirName && dirName[0] && dirName[0] != ' ') { + if (!lfile->Get(dirName)) { + lfile->mkdir(dirName); + } + lfile->cd(dirName); + } + LOGP(info, "Writing histograms to: {}/{}", lfile->GetPath(), dirName); + + for (int i = 0; i < GetLast() + 1; ++i) { + TObject* obj = UncheckedAt(i); + if (!obj) { + continue; + } + auto* histo = dynamic_cast(obj); + TDirectory* dr = nullptr; + if (histo) { + dr = histo->GetDirectory(); + histo->SetDirectory(nullptr); + } + obj->Write(nullptr, TObject::kOverwrite); + if (dr && histo) { + histo->SetDirectory(dr); + } + } + + if (localFile) { + lfile->Close(); + delete lfile; + } + auto* oldDir = static_cast(gROOT->GetListOfFiles()->FindObject(pwd.Data())); + if (oldDir) { + oldDir->cd(); + } +} + +void HistoManager::Clear(Option_t*) +{ + int nent = GetLast() + 1; + for (int i = 0; i < nent; ++i) { + TObject* hh = UncheckedAt(i); + if (!hh) { + continue; + } + RemoveAt(i); + --mNHistos; + } +} + +//_______________________________________________________________ +void HistoManager::Delete(Option_t*) +{ + int nent = GetLast() + 1; + for (int i = 0; i < nent; ++i) { + TObject* hh = UncheckedAt(i); + if (!hh) { + continue; + } + RemoveAt(i); + delete hh; + } + mNHistos = 0; +} + +void HistoManager::Print(Option_t* option) const +{ + int nent = GetLast() + 1; + for (int i = 0; i < nent; ++i) { + TObject* hh = UncheckedAt(i); + if (!hh) { + continue; + } + LOGP(info, "At position #{}", i); + hh->Print(option); + } + LOGP(info, "Total number of defined histograms: %d", mNHistos); + LOGP(info, "Current output path: {}/{}", mDefName, mDirName); +} + +void HistoManager::addPrefix(const std::string& pref) +{ + if (pref.empty()) { + return; + } + int nent = GetLast() + 1; + for (int i = 0; i < nent; ++i) { + TObject* hh = UncheckedAt(i); + if (!hh) { + continue; + } + if (hh->InheritsFrom("TNamed")) { + auto name = pref + hh->GetName(); + static_cast(hh)->SetName(name.c_str()); + } + } +} + +void HistoManager::addHistos(const HistoManager* hm, Double_t c1) +{ + if (!hm) { + return; + } + int nent = GetLast() + 1; + int nent1 = hm->GetLast() + 1; + if (nent != nent1) { + Error("addHistos", "HistoManagers have different content: %d vs %d", nent, nent1); + return; + } + for (int i = 0; i < nent; ++i) { + TH1* hh1 = getHisto(i); + TH1* hh2 = hm->getHisto(i); + if (!hh1 || !hh2) { + continue; + } + hh1->Add(hh2, c1); + } +} + +void HistoManager::divideHistos(const HistoManager* hm) +{ + if (!hm) { + return; + } + int nent = GetLast() + 1; + int nent1 = hm->GetLast() + 1; + if (nent != nent1) { + Error("divideHistos", "HistoManagers have different content: %d vs %d", nent, nent1); + return; + } + for (int i = 0; i < nent; ++i) { + TH1* hh1 = getHisto(i); + TH1* hh2 = hm->getHisto(i); + if (!hh1 || !hh2) { + continue; + } + hh1->Divide(hh2); + } +} + +//_______________________________________________________________ +void HistoManager::multiplyHistos(const HistoManager* hm) +{ + if (!hm) { + return; + } + int nent = GetLast() + 1; + int nent1 = hm->GetLast() + 1; + if (nent != nent1) { + Error("multiplyHistos", "HistoManagers have different content: %d vs %d", nent, nent1); + return; + } + for (int i = 0; i < nent; ++i) { + TH1* hh1 = getHisto(i); + TH1* hh2 = hm->getHisto(i); + if (!hh1 || !hh2) { + continue; + } + hh1->Multiply(hh2); + } +} + +void HistoManager::scaleHistos(Double_t c1) +{ + int nent = GetLast() + 1; + for (int i = 0; i < nent; ++i) { + TH1* hh1 = getHisto(i); + if (hh1) { + hh1->Scale(c1); + } + } +} + +void HistoManager::sumw2() +{ + int nent = GetLast() + 1; + for (int i = 0; i < nent; ++i) { + auto* hh1 = dynamic_cast(UncheckedAt(i)); + if (hh1) { + hh1->Sumw2(); + } + } +} + +void HistoManager::setFile(TFile* file) +{ + if (file) { + mDefName = file->GetName(); + } +} + +void HistoManager::delHisto(int at) +{ + TH1* hist = getHisto(at); + if (hist) { + RemoveAt(at); + delete hist; + --mNHistos; + } +} + +void HistoManager::purify(bool emptyToo) +{ + int last = GetLast() + 1; + if (emptyToo) { + for (int i = 0; i < last; ++i) { + TH1* hist = getHisto(i); + if (!hist) { + continue; + } + if (hist->GetEntries() < 1) { + delHisto(i); + } + } + } + Compress(); +} + +void HistoManager::setFileName(const std::string& name) +{ + mDefName = gSystem->ExpandPathName(name.c_str()); +} + +void HistoManager::reset() +{ + int last = GetLast() + 1; + for (int i = 0; i < last; ++i) { + TH1* hist = getHisto(i); + if (!hist) { + continue; + } + hist->Reset(); + } +} + +int HistoManager::load(const std::string& fname, const std::string& dirname) +{ + TFile* file = TFile::Open(gSystem->ExpandPathName(fname.c_str())); + if (!file) { + LOGP(error, "No file {}", fname); + return 0; + } + if (!dirname.empty() && dirname[0] != ' ') { + if (!file->Get(dirname.c_str())) { + LOGP(error, "No {} directory in file {}", dirname, fname); + file->Close(); + delete file; + return 0; + } + file->cd(dirname.c_str()); + } + int count = 0; + TList* lst = gDirectory->GetListOfKeys(); + TIter nextKey(lst); + TKey* key = nullptr; + while ((key = static_cast(nextKey()))) { + if (FindObject(key->GetName())) { + continue; + } + TString clName = key->GetClassName(); + if (!(clName.BeginsWith("TH") || clName.BeginsWith("TProfile") || clName.BeginsWith("TGraph"))) { + printf("Object %s of type %s is not processed\n", key->GetName(), clName.Data()); + continue; + } + TObject* hst = key->ReadObj(); + int id = hst->GetUniqueID(); + if (auto* h = dynamic_cast(hst)) { + addHisto(h, id - 1); + ++count; + continue; + } + if (auto* gr = dynamic_cast(hst)) { + addGraph(gr, id - 1); + ++count; + } + } + file->Close(); + delete file; + auto nm = fname; + if (!dirname.empty()) { + nm += fmt::format("/{}", dirname); + } + SetName(nm.c_str()); + return count; +} + +void HistoManager::setColor(int tcolor) +{ + int last = GetLast() + 1; + for (int i = 0; i < last; ++i) { + TH1* hist = getHisto(i); + if (!hist) { + continue; + } + hist->SetLineColor(tcolor); + hist->SetMarkerColor(tcolor); + TList* lst = hist->GetListOfFunctions(); + if (lst) { + int nf = lst->GetSize(); + for (int j = 0; j < nf; ++j) { + TObject* fnc = lst->At(j); + if (fnc->InheritsFrom("TF1")) { + static_cast(fnc)->SetLineColor(tcolor); + static_cast(fnc)->SetLineWidth(1); + static_cast(fnc)->ResetBit(TF1::kNotDraw); + } else if (fnc->InheritsFrom("TPaveStats")) { + static_cast(fnc)->SetTextColor(tcolor); + } + } + } + } +} + +void HistoManager::setMarkerStyle(Style_t mstyle, Size_t msize) +{ + int last = GetLast() + 1; + for (int i = 0; i < last; ++i) { + TH1* hist = getHisto(i); + if (!hist) { + continue; + } + hist->SetMarkerStyle(mstyle); + hist->SetMarkerSize(msize); + } +} + +void HistoManager::setMarkerSize(Size_t msize) +{ + int last = GetLast() + 1; + for (int i = 0; i < last; ++i) { + TH1* hist = getHisto(i); + if (!hist) { + continue; + } + hist->SetMarkerSize(msize); + } +} + +} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/study/src/SVStudy.cxx b/Detectors/GlobalTrackingWorkflow/study/src/SVStudy.cxx index 1e141a29d3f55..4d0b6bdbdb213 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/SVStudy.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/SVStudy.cxx @@ -29,7 +29,7 @@ #include "Framework/ConfigParamRegistry.h" #include "Framework/CCDBParamSpec.h" #include "FT0Reconstruction/InteractionTag.h" -#include "ITSMFTBase/DPLAlpideParam.h" +#include "DataFormatsITSMFT/DPLAlpideParam.h" #include "DetectorsCommonDataFormats/DetID.h" #include "DetectorsBase/GRPGeomHelper.h" #include "GlobalTrackingStudy/TrackingStudy.h" @@ -68,7 +68,7 @@ using V0ID = o2::dataformats::V0Index; using timeEst = o2::dataformats::TimeStampWithError; -class SVStudySpec : public Task +class SVStudySpec final : public Task { public: SVStudySpec(std::shared_ptr dr, std::shared_ptr gr, GTrackID::mask_t src, bool useTPCCl, bool useMC) diff --git a/Detectors/GlobalTrackingWorkflow/study/src/TPCClusSelector.cxx b/Detectors/GlobalTrackingWorkflow/study/src/TPCClusSelector.cxx new file mode 100644 index 0000000000000..e5b28fb0fd62b --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/src/TPCClusSelector.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. + +// helper class for TPC clusters selection +#include "GlobalTrackingStudy/TPCClusSelector.h" +#include "DataFormatsTPC/ClusterNativeHelper.h" +#include "Framework/Logger.h" +#include +#ifdef WITH_OPENMP +#include +#endif + +using namespace o2::tpc; + +void TPCClusSelector::setNThreads(int n) +{ +#ifndef WITH_OPENMP + if (n > 1) { + LOGP(warn, "No OpenMP"); + } + n = 1; +#endif + mNThreads = n; +} + +std::pair TPCClusSelector::findClustersRange(int sec, int row, float tbmin, float tbmax, const o2::tpc::ClusterNativeAccess& tpcClusterIdxStruct) +{ + // find sorted indices of clusters in the [tbmin:tbmax] range, if not found, return {-1,-2} + const auto& vidx = mSectors[sec].rows[row]; + const auto* clarr = tpcClusterIdxStruct.clusters[sec][row]; + // use binary search to find 1st cluster with time >= tb + int ncl = vidx.size(), left = 0, right = ncl; + while (left < right) { + int mid = left + (right - left) / 2; + if (clarr[vidx[mid]].getTime() < tbmin) { + left = mid + 1; + } else { + right = mid; + } + } + if (left == ncl || clarr[vidx[left]].getTime() > tbmax) { + return {-1, -2}; // all clusters have time < tbmin or no clusters in the range [tbmin:tbmax] + } + int idmin = left, idmax = left, idtst = idmin; + // look at smaller times + while (++idtst < ncl && clarr[vidx[idtst]].getTime() <= tbmax) { + idmax = idtst; + } + return {idmin, idmax}; +} + +int TPCClusSelector::findClustersEntries(int sec, int row, float tbmin, float tbmax, float padmin, float padmax, const o2::tpc::ClusterNativeAccess& tpcClusterIdxStruct, std::vector* clIDDirect) +{ + // find direct cluster indices for tbmin:tbmas / padmin/padmax range, fill clIDDirect vector if provided + const auto& vidx = mSectors[sec].rows[row]; + const auto* clarr = tpcClusterIdxStruct.clusters[sec][row]; + // use binary search to find 1st cluster with time >= tb + int ncl = vidx.size(), left = 0, right = ncl; + if (clIDDirect) { + clIDDirect->clear(); + } + while (left < right) { + int mid = left + (right - left) / 2; + if (clarr[vidx[mid]].getTime() < tbmin) { + left = mid + 1; + } else { + right = mid; + } + } + if (left == ncl || clarr[vidx[left]].getTime() > tbmax) { + return 0; // all clusters have time < tbmin or no clusters in the range [tbmin:tbmax] + } + int nclf = 0; + while (left < ncl) { + const auto& cl = clarr[vidx[left]]; + if (cl.getTime() > tbmax) { + break; + } + if (cl.getPad() >= padmin && cl.getPad() <= padmax) { + nclf++; + if (clIDDirect) { + clIDDirect->push_back(vidx[left]); + } + } + } + return nclf; +} + +void TPCClusSelector::fill(const o2::tpc::ClusterNativeAccess& tpcClusterIdxStruct) +{ + for (int is = 0; is < NSectors; is++) { + auto& sect = mSectors[is]; +#ifdef WITH_OPENMP +#pragma omp parallel for schedule(dynamic) num_threads(mNThreads) +#endif + for (int ir = 0; ir < Sector::NRows; ir++) { + size_t ncl = tpcClusterIdxStruct.nClusters[is][ir]; + if (ncl >= 0xffff) { + LOGP(error, "Row {} of sector {} has {} clusters, truncating to {}", ir, is, ncl, int(0xffff)); + ncl = 0xffff; + } + auto& rowidx = sect.rows[ir]; + rowidx.resize(ncl); + std::iota(rowidx.begin(), rowidx.end(), 0); + const auto* clus = tpcClusterIdxStruct.clusters[is][ir]; // C array of clusters + std::sort(rowidx.begin(), rowidx.end(), [&](size_t a, size_t b) { return clus[a].getTime() < clus[b].getTime(); }); + } + } +} diff --git a/Detectors/GlobalTrackingWorkflow/study/src/TPCTrackStudy.cxx b/Detectors/GlobalTrackingWorkflow/study/src/TPCTrackStudy.cxx index 1cb108da5a460..f9ba67319e18a 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/TPCTrackStudy.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/TPCTrackStudy.cxx @@ -14,7 +14,7 @@ #include "DataFormatsGlobalTracking/RecoContainer.h" #include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" #include "TPCCalibration/VDriftHelper.h" -#include "TPCCalibration/CorrectionMapsLoader.h" +#include "TPCFastTransformPOD.h" #include "ReconstructionDataFormats/GlobalTrackID.h" #include "DetectorsBase/Propagator.h" #include "DetectorsBase/GeometryManager.h" @@ -47,15 +47,11 @@ using TBracket = o2::math_utils::Bracketf_t; using timeEst = o2::dataformats::TimeStampWithError; -class TPCTrackStudySpec : public Task +class TPCTrackStudySpec final : public Task { public: - TPCTrackStudySpec(std::shared_ptr dr, std::shared_ptr gr, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, GTrackID::mask_t src, bool useMC) - : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mUseMC(useMC) - { - mTPCCorrMapsLoader.setLumiScaleType(sclOpts.lumiType); - mTPCCorrMapsLoader.setLumiScaleMode(sclOpts.lumiMode); - } + TPCTrackStudySpec(std::shared_ptr dr, std::shared_ptr gr, GTrackID::mask_t src, bool useMC) + : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mUseMC(useMC) {} ~TPCTrackStudySpec() final = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -68,7 +64,7 @@ class TPCTrackStudySpec : public Task std::shared_ptr mDataRequest; std::shared_ptr mGGCCDBRequest; o2::tpc::VDriftHelper mTPCVDriftHelper{}; - o2::tpc::CorrectionMapsLoader mTPCCorrMapsLoader{}; + const o2::gpu::TPCFastTransformPOD* mTPCCorrMaps{nullptr}; bool mUseMC{false}; ///< MC flag bool mUseGPUModel{false}; float mXRef = 0.; @@ -107,7 +103,6 @@ void TPCTrackStudySpec::init(InitContext& ic) if (mXRef < 0.) { mXRef = 0.; } - mTPCCorrMapsLoader.init(ic); mDBGOut = std::make_unique("tpc-trackStudy.root", "recreate"); if (ic.options().get("dump-clusters")) { mDBGOutCl = std::make_unique("tpc-trackStudy-cl.root", "recreate"); @@ -138,29 +133,13 @@ void TPCTrackStudySpec::updateTimeDependentParams(ProcessingContext& pc) { o2::base::GRPGeomHelper::instance().checkUpdates(pc); mTPCVDriftHelper.extractCCDBInputs(pc); - mTPCCorrMapsLoader.extractCCDBInputs(pc); + auto const& raw = pc.inputs().get("corrMap"); + mTPCCorrMaps = &o2::gpu::TPCFastTransformPOD::get(raw); static bool initOnceDone = false; if (!initOnceDone) { // this params need to be queried only once initOnceDone = true; // none at the moment } - // we may have other params which need to be queried regularly - bool updateMaps = false; - if (mTPCCorrMapsLoader.isUpdated()) { - mTPCCorrMapsLoader.acknowledgeUpdate(); - updateMaps = true; - } - if (mTPCVDriftHelper.isUpdated()) { - LOGP(info, "Updating TPC fast transform map with new VDrift factor of {} wrt reference {} and DriftTimeOffset correction {} wrt {} from source {}", - mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, - mTPCVDriftHelper.getVDriftObject().timeOffsetCorr, mTPCVDriftHelper.getVDriftObject().refTimeOffset, - mTPCVDriftHelper.getSourceName()); - mTPCVDriftHelper.acknowledgeUpdate(); - updateMaps = true; - } - if (updateMaps) { - mTPCCorrMapsLoader.updateVDrift(mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, mTPCVDriftHelper.getVDriftObject().getTimeOffset()); - } } void TPCTrackStudySpec::process(o2::globaltracking::RecoContainer& recoData) @@ -186,8 +165,7 @@ void TPCTrackStudySpec::process(o2::globaltracking::RecoContainer& recoData) } if (mTPCTracksArray.size()) { LOGP(info, "Found {} TPC tracks", mTPCTracksArray.size()); - mTPCRefitter = std::make_unique(mTPCClusterIdxStruct, &mTPCCorrMapsLoader, prop->getNominalBz(), mTPCTrackClusIdx.data(), 0, mTPCRefitterShMap.data(), mTPCRefitterOccMap.data(), mTPCRefitterOccMap.size(), nullptr, o2::base::Propagator::Instance()); - mTPCRefitter->setTrackReferenceX(900); // disable propagation after refit by setting reference to value > 500 + mTPCRefitter = std::make_unique(mTPCClusterIdxStruct, mTPCCorrMaps, prop->getNominalBz(), mTPCTrackClusIdx.data(), 0, mTPCRefitterShMap.data(), mTPCRefitterOccMap.data(), mTPCRefitterOccMap.size(), nullptr, o2::base::Propagator::Instance()); } float vdriftTB = mTPCVDriftHelper.getVDriftObject().getVDrift() * o2::tpc::ParameterElectronics::Instance().ZbinWidth; // VDrift expressed in cm/TimeBin float tpcTBBias = mTPCVDriftHelper.getVDriftObject().getTimeOffset() / (8 * o2::constants::lhc::LHCBunchSpacingMUS); @@ -196,7 +174,7 @@ void TPCTrackStudySpec::process(o2::globaltracking::RecoContainer& recoData) auto dumpClusters = [this] { static int tf = 0; - const auto* corrMap = this->mTPCCorrMapsLoader.getCorrMap(); + const auto* corrMap = this->mTPCCorrMaps; for (int sector = 0; sector < 36; sector++) { float alp = ((sector % 18) * 20 + 10) * TMath::DegToRad(); float sn = TMath::Sin(alp), cs = TMath::Cos(alp); @@ -273,7 +251,7 @@ void TPCTrackStudySpec::process(o2::globaltracking::RecoContainer& recoData) clSector.push_back(sector); clRow.push_back(row); float x, y, z; - mTPCCorrMapsLoader.Transform(sector, row, cl->getPad(), cl->getTime(), x, y, z, t); // nominal time of the track + mTPCCorrMaps->Transform(sector, row, cl->getPad(), cl->getTime(), x, y, z, t); // nominal time of the track clX.push_back(x); clY.push_back(y); clZ.push_back(z); @@ -415,12 +393,9 @@ void TPCTrackStudySpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) { return; } - if (mTPCCorrMapsLoader.accountCCDBInputs(matcher, obj)) { - return; - } } -DataProcessorSpec getTPCTrackStudySpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool useMC, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts) +DataProcessorSpec getTPCTrackStudySpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool useMC) { std::vector outputs; Options opts{ @@ -445,13 +420,13 @@ DataProcessorSpec getTPCTrackStudySpec(GTrackID::mask_t srcTracks, GTrackID::mas dataRequest->inputs, true); o2::tpc::VDriftHelper::requestCCDBInputs(dataRequest->inputs); - o2::tpc::CorrectionMapsLoader::requestCCDBInputs(dataRequest->inputs, opts, sclOpts); + dataRequest->inputs.emplace_back("corrMap", o2::header::gDataOriginTPC, "TPCCORRMAP", 0, Lifetime::Timeframe); return DataProcessorSpec{ "tpc-track-study", dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, sclOpts, srcTracks, useMC)}, + AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, srcTracks, useMC)}, opts}; } diff --git a/Detectors/GlobalTrackingWorkflow/study/src/TrackMCStudy.cxx b/Detectors/GlobalTrackingWorkflow/study/src/TrackMCStudy.cxx index d380a4f05cedf..9637c72589196 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/TrackMCStudy.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/TrackMCStudy.cxx @@ -17,13 +17,15 @@ #include "ReconstructionDataFormats/TrackTPCITS.h" #include "ReconstructionDataFormats/GlobalTrackID.h" #include "TPCCalibration/VDriftHelper.h" -#include "TPCCalibration/CorrectionMapsLoader.h" #include "ITSMFTReconstruction/ChipMappingITS.h" +#include "ITStracking/IOUtils.h" #include "DetectorsBase/Propagator.h" #include "DetectorsBase/GeometryManager.h" +#include "ITSBase/GeometryTGeo.h" #include "SimulationDataFormat/MCEventLabel.h" #include "SimulationDataFormat/MCUtils.h" #include "SimulationDataFormat/O2DatabasePDG.h" +#include "SimulationDataFormat/TrackReference.h" #include "CommonDataFormat/BunchFilling.h" #include "CommonUtils/NameConf.h" #include "DataFormatsFT0/RecPoints.h" @@ -31,7 +33,7 @@ #include "Framework/ConfigParamRegistry.h" #include "Framework/CCDBParamSpec.h" #include "FT0Reconstruction/InteractionTag.h" -#include "ITSMFTBase/DPLAlpideParam.h" +#include "DataFormatsITSMFT/DPLAlpideParam.h" #include "DetectorsCommonDataFormats/DetID.h" #include "DetectorsBase/GRPGeomHelper.h" #include "GlobalTrackingStudy/TrackMCStudy.h" @@ -54,6 +56,7 @@ #include "GPUParam.h" #include "GPUParam.inc" #include "MathUtils/fit.h" +#include "TPCFastTransformPOD.h" #include #include #include @@ -80,15 +83,11 @@ using TBracket = o2::math_utils::Bracketf_t; using timeEst = o2::dataformats::TimeStampWithError; -class TrackMCStudy : public Task +class TrackMCStudy final : public Task { public: - TrackMCStudy(std::shared_ptr dr, std::shared_ptr gr, GTrackID::mask_t src, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, bool checkSV) - : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mCheckSV(checkSV) - { - mTPCCorrMapsLoader.setLumiScaleType(sclOpts.lumiType); - mTPCCorrMapsLoader.setLumiScaleMode(sclOpts.lumiMode); - } + TrackMCStudy(std::shared_ptr dr, std::shared_ptr gr, GTrackID::mask_t src, bool checkSV) + : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mCheckSV(checkSV) {} ~TrackMCStudy() final = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -98,6 +97,7 @@ class TrackMCStudy : public Task private: void processTPCTrackRefs(); + void processITSTracks(const o2::globaltracking::RecoContainer& recoData); void loadTPCOccMap(const o2::globaltracking::RecoContainer& recoData); void fillMCClusterInfo(const o2::globaltracking::RecoContainer& recoData); void prepareITSData(const o2::globaltracking::RecoContainer& recoData); @@ -109,21 +109,25 @@ class TrackMCStudy : public Task void updateTimeDependentParams(ProcessingContext& pc); float getDCAYCut(float pt) const; - gsl::span mCurrMCTracks; + const std::vector* mCurrMCTracks = nullptr; TVector3 mCurrMCVertex; o2::tpc::VDriftHelper mTPCVDriftHelper{}; - o2::tpc::CorrectionMapsLoader mTPCCorrMapsLoader{}; + const o2::gpu::TPCFastTransformPOD* mTPCCorrMaps{nullptr}; std::shared_ptr mDataRequest; std::shared_ptr mGGCCDBRequest; std::unique_ptr mDBGOut; - std::vector mTBinClOcc; ///< TPC occupancy histo: i-th entry is the integrated occupancy for ~1 orbit starting from the TB = i*mNTPCOccBinLength - std::vector mTBinClOccHist; //< original occupancy - std::vector mIntBC; ///< interaction global BC wrt TF start - std::vector mTPCOcc; ///< TPC occupancy for this interaction time - std::vector mITSOcc; //< N ITS clusters in the ROF containing collision - bool mCheckSV = false; //< check SV binding (apart from prongs availability) - int mNTPCOccBinLength = 0; ///< TPC occ. histo bin length in TBs - float mNTPCOccBinLengthInv; + std::vector mTBinClOcc; ///< TPC occupancy histo: i-th entry is the integrated occupancy for ~1 orbit starting from the TB = i*mNTPCOccBinLength + std::vector mTBinClOccHist; //< original occupancy + std::vector mIntBC; ///< interaction global BC wrt TF start + std::vector mTPCOcc; ///< TPC occupancy for this interaction time + std::vector mITSOcc; //< N ITS clusters in the ROF containing collision + std::vector> mITSClustersArray; ///< ITS clusters created in run() method from compact clusters + const o2::itsmft::TopologyDictionary* mITSDict = nullptr; ///< cluster patterns dictionary + + bool mCheckSV = false; //< check SV binding (apart from prongs availability) + bool mRecProcStage = false; //< flag that the MC particle was added only at the stage of reco tracks processing + int mNTPCOccBinLength = 0; ///< TPC occ. histo bin length in TBs + float mNTPCOccBinLengthInv = -1.f; int mVerbose = 0; float mITSTimeBiasMUS = 0.f; float mITSROFrameLengthMUS = 0.f; ///< ITS RO frame in mus @@ -170,7 +174,6 @@ void TrackMCStudy::init(InitContext& ic) mNCheckDecays++; } mDecaysMaps.resize(mNCheckDecays); - mTPCCorrMapsLoader.init(ic); } void TrackMCStudy::run(ProcessingContext& pc) @@ -181,10 +184,11 @@ void TrackMCStudy::run(ProcessingContext& pc) } mDecProdLblPool.clear(); mMCVtVec.clear(); - mCurrMCTracks = {}; + mCurrMCTracks = nullptr; recoData.collectData(pc, *mDataRequest.get()); // select tracks of needed type, with minimal cuts, the real selected will be done in the vertexer updateTimeDependentParams(pc); // Make sure this is called after recoData.collectData, which may load some conditions + mRecProcStage = false; process(recoData); } @@ -192,23 +196,8 @@ void TrackMCStudy::updateTimeDependentParams(ProcessingContext& pc) { o2::base::GRPGeomHelper::instance().checkUpdates(pc); mTPCVDriftHelper.extractCCDBInputs(pc); - mTPCCorrMapsLoader.extractCCDBInputs(pc); - bool updateMaps = false; - if (mTPCCorrMapsLoader.isUpdated()) { - mTPCCorrMapsLoader.acknowledgeUpdate(); - updateMaps = true; - } - if (mTPCVDriftHelper.isUpdated()) { - LOGP(info, "Updating TPC fast transform map with new VDrift factor of {} wrt reference {} and DriftTimeOffset correction {} wrt {} from source {}", - mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, - mTPCVDriftHelper.getVDriftObject().timeOffsetCorr, mTPCVDriftHelper.getVDriftObject().refTimeOffset, - mTPCVDriftHelper.getSourceName()); - mTPCVDriftHelper.acknowledgeUpdate(); - updateMaps = true; - } - if (updateMaps) { - mTPCCorrMapsLoader.updateVDrift(mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, mTPCVDriftHelper.getVDriftObject().getTimeOffset()); - } + auto const& raw = pc.inputs().get("corrMap"); + mTPCCorrMaps = &o2::gpu::TPCFastTransformPOD::get(raw); static bool initOnceDone = false; if (!initOnceDone) { // this params need to be queried only once initOnceDone = true; @@ -218,7 +207,7 @@ void TrackMCStudy::updateTimeDependentParams(ProcessingContext& pc) auto& elParam = o2::tpc::ParameterElectronics::Instance(); mTPCTBinMUS = elParam.ZbinWidth; - + o2::its::GeometryTGeo::Instance()->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2GRot) | o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L)); if (mCheckSV) { const auto& svparam = o2::vertexing::SVertexerParams::Instance(); mFitterV0.setBz(o2::base::Propagator::Instance()->getNominalBz()); @@ -250,8 +239,8 @@ void TrackMCStudy::process(const o2::globaltracking::RecoContainer& recoData) auto vtxRefs = recoData.getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs auto prop = o2::base::Propagator::Instance(); int nv = vtxRefs.size(); - float vdriftTB = mTPCVDriftHelper.getVDriftObject().getVDrift() * o2::tpc::ParameterElectronics::Instance().ZbinWidth; // VDrift expressed in cm/TimeBin - float itsBias = 0.5 * mITSROFrameLengthMUS + o2::itsmft::DPLAlpideParam::Instance().roFrameBiasInBC * o2::constants::lhc::LHCBunchSpacingMUS; // ITS time is supplied in \mus as beginning of ROF + float vdriftTB = mTPCVDriftHelper.getVDriftObject().getVDrift() * o2::tpc::ParameterElectronics::Instance().ZbinWidth; // VDrift expressed in cm/TimeBin + float itsBias = 0.5 * mITSROFrameLengthMUS + o2::itsmft::DPLAlpideParam::Instance().roFrameBiasInBC * o2::constants::lhc::LHCBunchSpacingMUS; // ITS time is supplied in \mus as beginning of ROF prepareITSData(recoData); loadTPCOccMap(recoData); @@ -278,15 +267,34 @@ void TrackMCStudy::process(const o2::globaltracking::RecoContainer& recoData) return patt; }; - auto getLowestPadrow = [&recoData](const o2::tpc::TrackTPC& trc) { + auto fillTPCClusterInfo = [&recoData](const o2::tpc::TrackTPC& trc, RecTrack& tref) { if (recoData.inputsTPCclusters) { - uint8_t clSect = 0, clRow = 0; + uint8_t clSect = 0, clRow = 0, lowestR = -1; uint32_t clIdx = 0; const auto clRefs = recoData.getTPCTracksClusterRefs(); - trc.getClusterReference(clRefs, trc.getNClusterReferences() - 1, clSect, clRow, clIdx); - return int(clRow); + const auto tpcClusAcc = recoData.getTPCClusters(); + const auto shMap = recoData.clusterShMapTPC; + for (int ic = 0; ic < trc.getNClusterReferences(); ic++) { // outside -> inside ordering, but on the sector boundaries backward jumps are possible + trc.getClusterReference(clRefs, ic, clSect, clRow, clIdx); + if (clRow < lowestR) { + tref.rowCountTPC++; + lowestR = clRow; + } + unsigned int absoluteIndex = tpcClusAcc.clusterOffset[clSect][clRow] + clIdx; + if (shMap[absoluteIndex] & o2::gpu::GPUTPCGMMergedTrackHit::flagShared) { + tref.nClTPCShared++; + } + } + tref.lowestPadRow = lowestR; + const auto& clus = tpcClusAcc.clusters[clSect][clRow][clIdx]; + int padFromEdge = int(clus.getPad()), npads = o2::gpu::GPUTPCGeometry::NPads(clRow); + if (padFromEdge > npads / 2) { + padFromEdge = npads - 1 - padFromEdge; + } + tref.padFromEdge = uint8_t(padFromEdge); + trc.getClusterReference(clRefs, 0, clSect, clRow, clIdx); + tref.rowMaxTPC = clRow; } - return -1; }; auto flagTPCClusters = [&recoData](const o2::tpc::TrackTPC& trc, o2::MCCompLabel lbTrc) { @@ -338,6 +346,21 @@ void TrackMCStudy::process(const o2::globaltracking::RecoContainer& recoData) } break; } + if (mNTPCOccBinLengthInv > 0.f) { + mcVtx.occTPCV.resize(params.nOccBinsDrift); + int grp = TMath::Max(1, TMath::Nint(params.nTBPerOccBin * mNTPCOccBinLengthInv)); + for (int ib = 0; ib < params.nOccBinsDrift; ib++) { + float smb = 0; + int tbs = occBin + TMath::Nint(ib * params.nTBPerOccBin * mNTPCOccBinLengthInv); + for (int ig = 0; ig < grp; ig++) { + if (tbs >= 0 && tbs < int(mTBinClOccHist.size())) { + smb += mTBinClOccHist[tbs]; + } + tbs++; + } + mcVtx.occTPCV[ib] = smb; + } + } if (rofCount >= ITSClusROFRec.size()) { mITSOcc.push_back(0); // IR after the last ROF } @@ -352,15 +375,17 @@ void TrackMCStudy::process(const o2::globaltracking::RecoContainer& recoData) int nev = mcReader.getNEvents(curSrcMC); bool okAccVtx = true; if (nev != (int)mMCVtVec.size()) { - LOGP(error, "source {} has {} events while {} MC vertices were booked", curSrcMC, nev, mMCVtVec.size()); + LOGP(debug, "source {} has {} events while {} MC vertices were booked", curSrcMC, nev, mMCVtVec.size()); okAccVtx = false; + if (nev > (int)mMCVtVec.size()) { // QED + continue; + } } for (curEvMC = 0; curEvMC < nev; curEvMC++) { if (mVerbose > 1) { LOGP(info, "Event {}", curEvMC); } - const auto& mt = mcReader.getTracks(curSrcMC, curEvMC); - mCurrMCTracks = gsl::span(mt.data(), mt.size()); + mCurrMCTracks = &mcReader.getTracks(curSrcMC, curEvMC); const_cast(mcReader.getMCEventHeader(curSrcMC, curEvMC)).GetVertex(mCurrMCVertex); if (okAccVtx) { auto& pos = mMCVtVec[curEvMC].pos; @@ -370,7 +395,7 @@ void TrackMCStudy::process(const o2::globaltracking::RecoContainer& recoData) pos[2] = mCurrMCVertex.Z(); } } - for (int itr = 0; itr < mCurrMCTracks.size(); itr++) { + for (int itr = 0; itr < mCurrMCTracks->size(); itr++) { processMCParticle(curSrcMC, curEvMC, itr); } } @@ -382,6 +407,7 @@ void TrackMCStudy::process(const o2::globaltracking::RecoContainer& recoData) } // add reconstruction info to MC particles. If MC particle was not selected before but was reconstrected, account MC info + mRecProcStage = true; // MC particles accepted only at this stage will be flagged for (int iv = 0; iv < nv; iv++) { if (mVerbose > 1) { LOGP(info, "processing PV {} of {}", iv, nv); @@ -416,11 +442,10 @@ void TrackMCStudy::process(const o2::globaltracking::RecoContainer& recoData) if (lbl.getSourceID() != curSrcMC || lbl.getEventID() != curEvMC) { curSrcMC = lbl.getSourceID(); curEvMC = lbl.getEventID(); - const auto& mt = mcReader.getTracks(curSrcMC, curEvMC); - mCurrMCTracks = gsl::span(mt.data(), mt.size()); + mCurrMCTracks = &mcReader.getTracks(curSrcMC, curEvMC); const_cast(mcReader.getMCEventHeader(curSrcMC, curEvMC)).GetVertex(mCurrMCVertex); } - if (!acceptMCCharged(mCurrMCTracks[lbl.getTrackID()], lbl)) { + if (!acceptMCCharged((*mCurrMCTracks)[lbl.getTrackID()], lbl)) { continue; } entry = mSelMCTracks.find(lbl); @@ -468,7 +493,7 @@ void TrackMCStudy::process(const o2::globaltracking::RecoContainer& recoData) } LOGP(info, "collected {} MC tracks", mSelMCTracks.size()); - if (params.minTPCRefsToExtractClRes > 0) { // prepare MC trackrefs for TPC + if (params.minTPCRefsToExtractClRes > 0 || params.storeTPCTrackRefs) { // prepare MC trackrefs for TPC processTPCTrackRefs(); } @@ -493,6 +518,15 @@ void TrackMCStudy::process(const o2::globaltracking::RecoContainer& recoData) } return lhs.gid.getSource() > rhs.gid.getSource(); }); + if (params.storeTPCTrackRefs) { + auto rft = mSelTRefIdx.find(entry.first); + if (rft != mSelTRefIdx.end()) { + auto rfent = rft->second; + for (int irf = rfent.first; irf < rfent.second; irf++) { + trackFam.mcTrackInfo.trackRefsTPC.push_back(mSelTRefs[irf]); + } + } + } // fill track params int tcnt = 0; for (auto& tref : tracks) { @@ -522,17 +556,39 @@ void TrackMCStudy::process(const o2::globaltracking::RecoContainer& recoData) tref.flags |= RecTrack::FakeITS; } } - if (msk[DetID::TPC] && trackFam.entITSTPC < 0) { // has both ITS and TPC contribution - trackFam.entITSTPC = tcnt; + if (msk[DetID::TPC]) { + if (trackFam.entITSTPC < 0) { // has both ITS and TPC contribution + trackFam.entITSTPC = tcnt; + } if (recoData.getTrackMCLabel(gidSet[GTrackID::ITSTPC]).isFake()) { tref.flags |= RecTrack::FakeITSTPC; } + + if (msk[DetID::TRD]) { + if (recoData.getTrackMCLabel(gidSet[GTrackID::ITSTPCTRD]).isFake()) { + tref.flags |= RecTrack::FakeTRD; + } + if (msk[DetID::TOF]) { + if (recoData.getTrackMCLabel(gidSet[GTrackID::ITSTPCTRDTOF]).isFake()) { + tref.flags |= RecTrack::FakeTOF; + } + } + } else { + if (msk[DetID::TOF]) { + if (recoData.getTrackMCLabel(gidSet[GTrackID::ITSTPCTOF]).isFake()) { + tref.flags |= RecTrack::FakeTOF; + } + } + } } } if (msk[DetID::TPC]) { const auto& trtpc = recoData.getTPCTrack(gidSet[GTrackID::TPC]); tref.nClTPC = trtpc.getNClusters(); - tref.lowestPadRow = getLowestPadrow(trtpc); + if (trtpc.hasBothSidesClusters()) { + tref.flags |= RecTrack::HASACSides; + } + fillTPCClusterInfo(trtpc, tref); flagTPCClusters(trtpc, entry.first); if (trackFam.entTPC < 0) { trackFam.entTPC = tcnt; @@ -541,6 +597,24 @@ void TrackMCStudy::process(const o2::globaltracking::RecoContainer& recoData) if (recoData.getTrackMCLabel(gidSet[GTrackID::TPC]).isFake()) { tref.flags |= RecTrack::FakeTPC; } + if (!msk[DetID::ITS]) { + if (msk[DetID::TRD]) { + if (recoData.getTrackMCLabel(gidSet[GTrackID::TPCTRD]).isFake()) { + tref.flags |= RecTrack::FakeTRD; + } + if (msk[DetID::TOF]) { + if (recoData.getTrackMCLabel(gidSet[GTrackID::TPCTRDTOF]).isFake()) { + tref.flags |= RecTrack::FakeTOF; + } + } + } else { + if (msk[DetID::TOF]) { + if (recoData.getTrackMCLabel(gidSet[GTrackID::TPCTOF]).isFake()) { + tref.flags |= RecTrack::FakeTOF; + } + } + } + } } float ts = 0, terr = 0; if (tref.gid.getSource() != GTrackID::ITS) { @@ -556,8 +630,8 @@ void TrackMCStudy::process(const o2::globaltracking::RecoContainer& recoData) tcnt++; } if (trackFam.entITS > -1 && trackFam.entTPC > -1) { // ITS and TPC were found but matching failed - auto vidITS = tracks[trackFam.entITS].gid; - auto vidTPC = tracks[trackFam.entTPC].gid; + auto vidITS = recoData.getITSContributorGID(tracks[trackFam.entITS].gid); + auto vidTPC = recoData.getTPCContributorGID(tracks[trackFam.entTPC].gid); auto trcTPC = recoData.getTrackParam(vidTPC); auto trcITS = recoData.getTrackParamOut(vidITS); if (propagateToRefX(trcTPC, trcITS)) { @@ -663,6 +737,10 @@ void TrackMCStudy::process(const o2::globaltracking::RecoContainer& recoData) }); (*mDBGOut) << "mcVtxTree" << "mcVtx=" << mcVtx << "\n"; } + + if (params.storeITSInfo) { + processITSTracks(recoData); + } } void TrackMCStudy::processTPCTrackRefs() @@ -723,8 +801,8 @@ void TrackMCStudy::fillMCClusterInfo(const o2::globaltracking::RecoContainer& re const auto& params = o2::trackstudy::TrackMCStudyConfig::Instance(); ClResTPC clRes{}; - for (uint8_t sector = 0; sector < 36; sector++) { - for (uint8_t row = 0; row < 152; row++) { + for (uint8_t row = 0; row < 152; row++) { // we need to go in increasing row, so this should be the outer loop + for (uint8_t sector = 0; sector < 36; sector++) { unsigned int offs = TPCClusterIdxStruct.clusterOffset[sector][row]; for (unsigned int icl0 = 0; icl0 < TPCClusterIdxStruct.nClusters[sector][row]; icl0++) { const auto labels = TPCClMClab->getLabels(icl0 + offs); @@ -772,7 +850,7 @@ void TrackMCStudy::fillMCClusterInfo(const o2::globaltracking::RecoContainer& re continue; } float xc, yc, zc; - mTPCCorrMapsLoader.Transform(sector, row, clus.getPad(), clus.getTime(), xc, yc, zc, mctr.bcInTF / 8.); // nominal time of the track + mTPCCorrMaps->Transform(sector, row, clus.getPad(), clus.getTime(), xc, yc, zc, mctr.bcInTF / 8.); // nominal time of the track const auto& entTRefIDs = entTRefIDsIt->second; // find bracketing TRef params @@ -924,9 +1002,6 @@ void TrackMCStudy::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) { return; } - if (mTPCCorrMapsLoader.accountCCDBInputs(matcher, obj)) { - return; - } if (matcher == ConcreteDataMatcher("ITS", "ALPIDEPARAM", 0)) { LOG(info) << "ITS Alpide param updated"; const auto& par = o2::itsmft::DPLAlpideParam::Instance(); @@ -935,6 +1010,11 @@ void TrackMCStudy::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) mITSROFrameLengthMUS = par.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingNS * 1e-3; return; } + if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) { + LOG(info) << "cluster dictionary updated"; + mITSDict = (const o2::itsmft::TopologyDictionary*)obj; + return; + } } //_____________________________________________________ @@ -968,7 +1048,7 @@ float TrackMCStudy::getDCAYCut(float pt) const bool TrackMCStudy::processMCParticle(int src, int ev, int trid) { - const auto& mcPart = mCurrMCTracks[trid]; + const auto& mcPart = (*mCurrMCTracks)[trid]; int pdg = mcPart.GetPdgCode(); bool res = false; while (true) { @@ -982,7 +1062,7 @@ bool TrackMCStudy::processMCParticle(int src, int ev, int trid) break; } } - if (decay >= 0) { // check if decay and kinematics is acceptable + if (decay >= 0) { // check if decay and kinematics is acceptable auto& decayPool = mDecaysMaps[decay]; int idd0 = mcPart.getFirstDaughterTrackId(), idd1 = mcPart.getLastDaughterTrackId(); // we want only charged and trackable daughters int dtStart = mDecProdLblPool.size(), dtEnd = -1; @@ -990,7 +1070,7 @@ bool TrackMCStudy::processMCParticle(int src, int ev, int trid) break; } for (int idd = idd0; idd <= idd1; idd++) { - const auto& product = mCurrMCTracks[idd]; + const auto& product = (*mCurrMCTracks)[idd]; auto lbld = o2::MCCompLabel(idd, ev, src); if (!acceptMCCharged(product, lbld, decay)) { decay = -1; // discard decay @@ -1088,10 +1168,17 @@ bool TrackMCStudy::addMCParticle(const MCTrack& mcPart, const o2::MCCompLabel& l mcEntry.mcTrackInfo.bcInTF = mIntBC[lb.getEventID()]; mcEntry.mcTrackInfo.occTPC = mTPCOcc[lb.getEventID()]; mcEntry.mcTrackInfo.occITS = mITSOcc[lb.getEventID()]; + mcEntry.mcTrackInfo.occTPCV = mMCVtVec[lb.getEventID()].occTPCV; + if (mRecProcStage) { + mcEntry.mcTrackInfo.setAddedAtRecStage(); + } + if (o2::mcutils::MCTrackNavigator::isPhysicalPrimary(mcPart, *mCurrMCTracks)) { + mcEntry.mcTrackInfo.setPrimary(); + } int moth = -1; o2::MCCompLabel mclbPar; if ((moth = mcPart.getMotherTrackId()) >= 0) { - const auto& mcPartPar = mCurrMCTracks[moth]; + const auto& mcPartPar = (*mCurrMCTracks)[moth]; mcEntry.mcTrackInfo.pdgParent = mcPartPar.GetPdgCode(); } if (mcPart.isPrimary() && mcReader.getNEvents(lb.getSourceID()) == mMCVtVec.size()) { @@ -1153,7 +1240,7 @@ void TrackMCStudy::loadTPCOccMap(const o2::globaltracking::RecoContainer& recoDa auto NHBPerTF = o2::base::GRPGeomHelper::instance().getGRPECS()->getNHBFPerTF(); const auto& TPCOccMap = recoData.occupancyMapTPC; auto prop = o2::base::Propagator::Instance(); - auto TPCRefitter = std::make_unique(&recoData.inputsTPCclusters->clusterIndex, &mTPCCorrMapsLoader, prop->getNominalBz(), + auto TPCRefitter = std::make_unique(&recoData.inputsTPCclusters->clusterIndex, mTPCCorrMaps, prop->getNominalBz(), recoData.getTPCTracksClusterRefs().data(), 0, recoData.clusterShMapTPC.data(), TPCOccMap.data(), TPCOccMap.size(), nullptr, prop); mNTPCOccBinLength = TPCRefitter->getParam()->rec.tpc.occupancyMapTimeBins; mTBinClOcc.clear(); @@ -1181,7 +1268,86 @@ void TrackMCStudy::loadTPCOccMap(const o2::globaltracking::RecoContainer& recoDa } } -DataProcessorSpec getTrackMCStudySpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, bool checkSV) +void TrackMCStudy::processITSTracks(const o2::globaltracking::RecoContainer& recoData) +{ + if (!mITSDict) { + LOGP(warn, "ITS data is not loaded"); + return; + } + const auto itsTracks = recoData.getITSTracks(); + const auto itsLbls = recoData.getITSTracksMCLabels(); + const auto itsClRefs = recoData.getITSTracksClusterRefs(); + const auto clusITS = recoData.getITSClusters(); + const auto patterns = recoData.getITSClustersPatterns(); + const auto& params = o2::trackstudy::TrackMCStudyConfig::Instance(); + auto pattIt = patterns.begin(); + mITSClustersArray.clear(); + mITSClustersArray.reserve(clusITS.size()); + + o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mITSDict); + auto geom = o2::its::GeometryTGeo::Instance(); + int ntr = itsLbls.size(); + LOGP(info, "We have {} ITS clusters and the number of patterns is {}, ITSdict:{} NMCLabels: {}", clusITS.size(), patterns.size(), mITSDict != nullptr, itsLbls.size()); + + std::vector evord(ntr); + std::iota(evord.begin(), evord.end(), 0); + std::sort(evord.begin(), evord.end(), [&](int i, int j) { return itsLbls[i] < itsLbls[j]; }); + std::vector outHitInfo; + std::array cl2arr{}; + + for (int itr0 = 0; itr0 < ntr; itr0++) { + auto itr = evord[itr0]; + const auto& itsTr = itsTracks[itr]; + const auto& itsLb = itsLbls[itr]; + // LOGP(info,"proc {} {} {}",itr0, itr, itsLb.asString()); + int nCl = itsTr.getNClusters(); + if (itsLb.isFake() || nCl < params.minITSClForITSoutput) { + continue; + } + auto entrySel = mSelMCTracks.find(itsLb); + if (entrySel == mSelMCTracks.end()) { + continue; + } + outHitInfo.clear(); + cl2arr.fill(-1); + auto clEntry = itsTr.getFirstClusterEntry(); + for (int iCl = nCl; iCl--;) { // clusters are stored from outer to inner layers + const auto& cls = mITSClustersArray[itsClRefs[clEntry + iCl]]; + int hpos = outHitInfo.size(); + auto& hinf = outHitInfo.emplace_back(); + hinf.clus = cls; + hinf.clus.setCount(geom->getLayer(cls.getSensorID())); + geom->getSensorXAlphaRefPlane(cls.getSensorID(), hinf.chipX, hinf.chipAlpha); + cl2arr[hinf.clus.getCount()] = hpos; // to facilitate finding the cluster of the layer + } + auto trspan = mcReader.getTrackRefs(itsLb.getSourceID(), itsLb.getEventID(), itsLb.getTrackID()); + int ilrc = -1, nrefAcc = 0; + for (const auto& trf : trspan) { + if (trf.getDetectorId() != 0) { // process ITS only + continue; + } + int lrt = trf.getUserId(); // layer of the reference, but there might be multiple hits on the same layer + int clEnt = cl2arr[lrt]; + if (clEnt < 0) { + continue; + } + auto& hinf = outHitInfo[clEnt]; + float traX, traY; + o2::math_utils::rotateZInv(trf.X(), trf.Y(), traX, traY, std::sin(hinf.chipAlpha), std::cos(hinf.chipAlpha)); // tracking coordinates of the reference + if (hinf.trefXT < 1 || std::abs(traX - hinf.chipX) < std::abs(hinf.trefXT - hinf.chipX)) { + if (hinf.trefXT < 1) { + nrefAcc++; + } + hinf.tref = trf; + hinf.trefXT = traX; + hinf.trefYT = traY; + } + } + (*mDBGOut) << "itsTree" << "hits=" << outHitInfo << "trIn=" << ((o2::track::TrackParCov&)itsTr) << "trOut=" << itsTr.getParamOut() << "mcTr=" << entrySel->second.mcTrackInfo.track << "mcPDG=" << entrySel->second.mcTrackInfo.pdg << "nTrefs=" << nrefAcc << "\n"; + } +} + +DataProcessorSpec getTrackMCStudySpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool checkSV) { std::vector outputs; Options opts{ @@ -1200,7 +1366,7 @@ DataProcessorSpec getTrackMCStudySpec(GTrackID::mask_t srcTracks, GTrackID::mask dataRequest->requestSecondaryVertices(useMC); } o2::tpc::VDriftHelper::requestCCDBInputs(dataRequest->inputs); - o2::tpc::CorrectionMapsLoader::requestCCDBInputs(dataRequest->inputs, opts, sclOpts); + dataRequest->inputs.emplace_back("corrMap", o2::header::gDataOriginTPC, "TPCCORRMAP", 0, Lifetime::Timeframe); auto ggRequest = std::make_shared(false, // orbitResetTime true, // GRPECS=true true, // GRPLHCIF @@ -1214,7 +1380,7 @@ DataProcessorSpec getTrackMCStudySpec(GTrackID::mask_t srcTracks, GTrackID::mask "track-mc-study", dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, srcTracks, sclOpts, checkSV)}, + AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, srcTracks, checkSV)}, opts}; } diff --git a/Detectors/GlobalTrackingWorkflow/study/src/TrackMCStudyTypes.cxx b/Detectors/GlobalTrackingWorkflow/study/src/TrackMCStudyTypes.cxx index 204e0c741a675..b6236b7bf0e73 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/TrackMCStudyTypes.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/TrackMCStudyTypes.cxx @@ -77,4 +77,66 @@ int MCTrackInfo::getHighestITSLayer() const return -1; } +o2::track::TrackPar MCTrackInfo::getTrackParTPC(float b, float x) const +{ + o2::track::TrackPar t(track); + int ntri = 0; + while (ntri < 2) { + int sector0 = o2::math_utils::angle2Sector(t.getAlpha()); + if (!t.propagateParamTo(x, b)) { + t.invalidate(); + break; + } + int sector = o2::math_utils::angle2Sector(t.getPhiPos()); + float alpha = o2::math_utils::sector2Angle(sector); + if (!t.rotateParam(alpha)) { + t.invalidate(); + break; + } + if (sector != sector0) { + ntri++; + continue; + } + break; + } + // printf("%s ->\n%s <-\n",track.asString().c_str(), t.asString().c_str()); + return t; +} + +float MCTrackInfo::getTrackParTPCPar(int i, float b, float x) const +{ + auto t = getTrackParTPC(b, x); + return t.isValid() ? t.getParam(i) : -999.; +} + +float MCTrackInfo::getTrackParTPCPhiSec(float b, float x) const +{ + auto t = getTrackParTPC(b, x); + return t.isValid() ? std::atan2(t.getY(), t.getX()) : -999.; +} + +int TrackFamily::getLongestTPCTrackEntry() const +{ + int n = -1, ncl = 0; + int ntr = recTracks.size(); + for (int i = 0; i < ntr; i++) { + if (recTracks[i].nClTPC > ncl) { + ncl = recTracks[i].nClTPC; + n = i; + } + } + return n; +} + +int TrackFamily::getNTPCClones() const +{ + int n = 0; + for (auto& t : recTracks) { + if (t.nClTPC > 0) { + n++; + } + } + return n; +} + } // namespace o2::trackstudy diff --git a/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx b/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx index f206c43f7f57a..881ce9041ae04 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx @@ -28,7 +28,7 @@ #include "Framework/CCDBParamSpec.h" #include "Framework/DeviceSpec.h" #include "FT0Reconstruction/InteractionTag.h" -#include "ITSMFTBase/DPLAlpideParam.h" +#include "DataFormatsITSMFT/DPLAlpideParam.h" #include "DetectorsCommonDataFormats/DetID.h" #include "DetectorsBase/GRPGeomHelper.h" #include "GlobalTrackingStudy/TrackingStudy.h" @@ -42,14 +42,14 @@ #include "ReconstructionDataFormats/VtxTrackRef.h" #include "ReconstructionDataFormats/DCA.h" #include "TPCCalibration/VDriftHelper.h" -#include "TPCCalibration/CorrectionMapsLoader.h" #include "GPUO2InterfaceRefit.h" -#include "GPUO2Interface.h" // Needed for propper settings in GPUParam.h +#include "GPUO2ExternalUser.h" // Needed for propper settings in GPUParam.h #include "GPUParam.h" #include "GPUParam.inc" #include "GPUTPCGeometry.h" #include "Steer/MCKinematicsReader.h" #include "MathUtils/fit.h" +#include "TPCFastTransformPOD.h" #include namespace o2::trackstudy @@ -67,15 +67,11 @@ using TBracket = o2::math_utils::Bracketf_t; using timeEst = o2::dataformats::TimeStampWithError; -class TrackingStudySpec : public Task +class TrackingStudySpec final : public Task { public: - TrackingStudySpec(std::shared_ptr dr, std::shared_ptr gr, GTrackID::mask_t src, bool useMC, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts) - : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mUseMC(useMC) - { - mTPCCorrMapsLoader.setLumiScaleType(sclOpts.lumiType); - mTPCCorrMapsLoader.setLumiScaleMode(sclOpts.lumiMode); - } + TrackingStudySpec(std::shared_ptr dr, std::shared_ptr gr, GTrackID::mask_t src, bool useMC) + : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mUseMC(useMC) {} ~TrackingStudySpec() final = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -90,12 +86,12 @@ class TrackingStudySpec : public Task std::shared_ptr mDataRequest; std::shared_ptr mGGCCDBRequest; o2::tpc::VDriftHelper mTPCVDriftHelper{}; - o2::tpc::CorrectionMapsLoader mTPCCorrMapsLoader{}; + const o2::gpu::TPCFastTransformPOD* mTPCCorrMaps{nullptr}; bool mUseMC{false}; ///< MC flag std::unique_ptr mDBGOut; std::unique_ptr mDBGOutVtx; - std::unique_ptr mTPCRefitter; ///< TPC refitter used for TPC tracks refit during the reconstruction - std::vector mTBinClOccAft, mTBinClOccBef, mTBinClOccWgh; ///< TPC occupancy histo: i-th entry is the integrated occupancy for ~1 orbit starting/preceding from the TB = i*mNTPCOccBinLength + std::unique_ptr mTPCRefitter; ///< TPC refitter used for TPC tracks refit during the reconstruction + std::vector mMltHistTB, mTBinClOccAft, mTBinClOccBef, mTBinClOccWgh; ///< TPC occupancy histo: i-th entry is the integrated occupancy for ~1 orbit starting/preceding from the TB = i*mNTPCOccBinLength std::unique_ptr mOccWghFun; float mITSROFrameLengthMUS = 0.f; float mTPCTBinMUS = 0.f; // TPC bin in microseconds @@ -107,6 +103,7 @@ class TrackingStudySpec : public Task float mMinX = 46.; float mMaxEta = 0.8; float mMinPt = 0.1; + int mNOccBinsDrift = 10; int mMinTPCClusters = 60; int mNTPCOccBinLength = 0; ///< TPC occ. histo bin length in TBs int mNHBPerTF = 0; @@ -123,7 +120,6 @@ class TrackingStudySpec : public Task void TrackingStudySpec::init(InitContext& ic) { o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); - mTPCCorrMapsLoader.init(ic); int lane = ic.services().get().inputTimesliceId; int maxLanes = ic.services().get().maxInputTimeslices; std::string dbgnm = maxLanes == 1 ? "trackStudy.root" : fmt::format("trackStudy_{}.root", lane); @@ -142,6 +138,10 @@ void TrackingStudySpec::init(InitContext& ic) mDCAYFormula = ic.options().get("dcay-vs-pt"); mDCAZFormula = ic.options().get("dcaz-vs-pt"); mDoPairsCorr = ic.options().get("pair-correlations"); + mNOccBinsDrift = ic.options().get("noccbins"); + if (mNOccBinsDrift < 3) { + mNOccBinsDrift = 3; + } auto str = ic.options().get("occ-weight-fun"); if (!str.empty()) { mOccWghFun = std::make_unique("occFun", str.c_str(), -100., 100.); @@ -154,10 +154,9 @@ void TrackingStudySpec::run(ProcessingContext& pc) recoData.collectData(pc, *mDataRequest.get()); // select tracks of needed type, with minimal cuts, the real selected will be done in the vertexer updateTimeDependentParams(pc); // Make sure this is called after recoData.collectData, which may load some conditions if (recoData.inputsTPCclusters) { - mTPCRefitter = std::make_unique(&recoData.inputsTPCclusters->clusterIndex, &mTPCCorrMapsLoader, o2::base::Propagator::Instance()->getNominalBz(), + mTPCRefitter = std::make_unique(&recoData.inputsTPCclusters->clusterIndex, mTPCCorrMaps, o2::base::Propagator::Instance()->getNominalBz(), recoData.getTPCTracksClusterRefs().data(), 0, recoData.clusterShMapTPC.data(), recoData.occupancyMapTPC.data(), recoData.occupancyMapTPC.size(), nullptr, o2::base::Propagator::Instance()); - mTPCRefitter->setTrackReferenceX(900); // disable propagation after refit by setting reference to value > 500 mNTPCOccBinLength = mTPCRefitter->getParam()->rec.tpc.occupancyMapTimeBins; mTBinClOccBef.clear(); mTBinClOccAft.clear(); @@ -172,42 +171,23 @@ void TrackingStudySpec::run(ProcessingContext& pc) mTBinClOccAft.resize(nTPCOccBins); mTBinClOccBef.resize(nTPCOccBins); float sm = 0., tb = 0.5 * mNTPCOccBinLength; - /* // at the moment not used - if (mOccWghFun) { - mTBinClOccWgh.resize(nTPCBins); - float occBin2MUS = 8 * o2::constants::lhc::LHCBunchSpacingMUS; - int covWghTB = TMath::NInt(100./occBin2MUS); // coverage of weighted occ. in TBins - for (int i = 0; i < nTPCBins; i++) { - sm = 0.; - for (int j=-covWghTB;j=nTPCBins) { - continue; - } - sm += mOccWghFun->Eval(j*occBin2MUS)*mTPCRefitter->getParam()->GetUnscaledMult(j+i); - } - mTBinClOccWgh[i] = sm; - } - } else { - mTBinClOccWgh.resize(1); - } - */ - std::vector mltHistTB(nTPCOccBins); + mMltHistTB.resize(nTPCOccBins); for (int i = 0; i < nTPCOccBins; i++) { - mltHistTB[i] = mTPCRefitter->getParam()->GetUnscaledMult(tb); + mMltHistTB[i] = mTPCRefitter->getParam()->GetUnscaledMult(tb); tb += mNTPCOccBinLength; } for (int i = nTPCOccBins; i--;) { - sm += mltHistTB[i]; + sm += mMltHistTB[i]; if (i + sumBins < nTPCOccBins) { - sm -= mltHistTB[i + sumBins]; + sm -= mMltHistTB[i + sumBins]; } mTBinClOccAft[i] = sm; } sm = 0; for (int i = 0; i < nTPCOccBins; i++) { - sm += mltHistTB[i]; + sm += mMltHistTB[i]; if (i - sumBins > 0) { - sm -= mltHistTB[i - sumBins]; + sm -= mMltHistTB[i - sumBins]; } mTBinClOccBef[i] = sm; } @@ -223,7 +203,8 @@ void TrackingStudySpec::updateTimeDependentParams(ProcessingContext& pc) { o2::base::GRPGeomHelper::instance().checkUpdates(pc); mTPCVDriftHelper.extractCCDBInputs(pc); - mTPCCorrMapsLoader.extractCCDBInputs(pc); + auto const& raw = pc.inputs().get("corrMap"); + mTPCCorrMaps = &o2::gpu::TPCFastTransformPOD::get(raw); static bool initOnceDone = false; if (!initOnceDone) { // this params need to be queried only once initOnceDone = true; @@ -241,22 +222,6 @@ void TrackingStudySpec::updateTimeDependentParams(ProcessingContext& pc) mTPCTBinMUS = elParam.ZbinWidth; // TPC bin in microseconds mTPCTBinMUSInv = 1. / mTPCTBinMUS; } - bool updateMaps = false; - if (mTPCCorrMapsLoader.isUpdated()) { - mTPCCorrMapsLoader.acknowledgeUpdate(); - updateMaps = true; - } - if (mTPCVDriftHelper.isUpdated()) { - LOGP(info, "Updating TPC fast transform map with new VDrift factor of {} wrt reference {} and DriftTimeOffset correction {} wrt {} from source {}", - mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, - mTPCVDriftHelper.getVDriftObject().timeOffsetCorr, mTPCVDriftHelper.getVDriftObject().refTimeOffset, - mTPCVDriftHelper.getSourceName()); - mTPCVDriftHelper.acknowledgeUpdate(); - updateMaps = true; - } - if (updateMaps) { - mTPCCorrMapsLoader.updateVDrift(mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, mTPCVDriftHelper.getVDriftObject().getTimeOffset()); - } } void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) @@ -271,44 +236,48 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) o2::dataformats::PrimaryVertexExt pveDummy; o2::dataformats::PrimaryVertexExt vtxDummy(mMeanVtx.getPos(), {}, {}, 0); std::vector pveVec(nv); + std::vector tpcOccAftV, tpcOccBefV; pveVec.back() = vtxDummy; const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); float tBiasITS = alpParams.roFrameBiasInBC * o2::constants::lhc::LHCBunchSpacingMUS; const o2::ft0::InteractionTag& ft0Params = o2::ft0::InteractionTag::Instance(); std::vector trcExtVec; std::vector trcPairsVec; - auto vdrit = mTPCVDriftHelper.getVDriftObject().getVDrift(); + auto vdrift = mTPCVDriftHelper.getVDriftObject().getVDrift(); + float maxDriftTB = 250.f / vdrift / (o2::constants::lhc::LHCBunchSpacingMUS * 8); + int groupOcc = std::ceil(maxDriftTB / mNOccBinsDrift / mNTPCOccBinLength); + bool tpcTrackOK = recoData.isTrackSourceLoaded(GTrackID::TPC); auto fillTPCClInfo = [&recoData, this](const o2::tpc::TrackTPC& trc, o2::dataformats::TrackInfoExt& trExt, float timestampTB = -1e9) { const auto clRefs = recoData.getTPCTracksClusterRefs(); const auto tpcClusAcc = recoData.getTPCClusters(); const auto shMap = recoData.clusterShMapTPC; + if (recoData.inputsTPCclusters) { - uint8_t clSect = 0, clRow = 0, clRowP = -1; + uint8_t clSect = 0, clRow = 0, lowestR = -1; uint32_t clIdx = 0; - for (int ic = 0; ic < trc.getNClusterReferences(); ic++) { + for (int ic = 0; ic < trc.getNClusterReferences(); ic++) { // outside -> inside ordering, but on the sector boundaries backward jumps are possible trc.getClusterReference(clRefs, ic, clSect, clRow, clIdx); - if (clRow != clRowP) { + if (clRow < lowestR) { trExt.rowCountTPC++; - clRowP = clRow; + lowestR = clRow; } unsigned int absoluteIndex = tpcClusAcc.clusterOffset[clSect][clRow] + clIdx; if (shMap[absoluteIndex] & o2::gpu::GPUTPCGMMergedTrackHit::flagShared) { trExt.nClTPCShared++; } } - trc.getClusterReference(clRefs, trc.getNClusterReferences() - 1, clSect, clRow, clIdx); - trExt.rowMinTPC = clRow; + trExt.rowMinTPC = lowestR; const auto& clus = tpcClusAcc.clusters[clSect][clRow][clIdx]; trExt.padFromEdge = uint8_t(clus.getPad()); - int npads = o2::gpu::GPUTPCGeometry::NPads(clRow); + int npads = o2::gpu::GPUTPCGeometry::NPads(lowestR); if (trExt.padFromEdge > npads / 2) { trExt.padFromEdge = npads - 1 - trExt.padFromEdge; } - this->mTPCCorrMapsLoader.Transform(clSect, clRow, clus.getPad(), clus.getTime(), trExt.innerTPCPos0[0], trExt.innerTPCPos0[1], trExt.innerTPCPos0[2], trc.getTime0()); // nominal time of the track + this->mTPCCorrMaps->Transform(clSect, clRow, clus.getPad(), clus.getTime(), trExt.innerTPCPos0[0], trExt.innerTPCPos0[1], trExt.innerTPCPos0[2], trc.getTime0()); // nominal time of the track if (timestampTB > -1e8) { - this->mTPCCorrMapsLoader.Transform(clSect, clRow, clus.getPad(), clus.getTime(), trExt.innerTPCPos[0], trExt.innerTPCPos[1], trExt.innerTPCPos[2], timestampTB); // time assigned from the global track track + this->mTPCCorrMaps->Transform(clSect, clRow, clus.getPad(), clus.getTime(), trExt.innerTPCPos[0], trExt.innerTPCPos[1], trExt.innerTPCPos[2], timestampTB); // time assigned from the global track track } else { trExt.innerTPCPos = trExt.innerTPCPos0; } @@ -324,9 +293,9 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) uint8_t clSect0 = 0, clRow0 = 0, clSect1 = 0, clRow1 = 0; uint32_t clIdx0 = 0, clIdx1 = 0; int ic1Start = 0; - for (int ic0 = 0; ic0 < trc0.getNClusterReferences(); ic0++) { // outside -> inside + for (int ic0 = 0; ic0 < trc0.getNClusterReferences(); ic0++) { // outside -> inside, but on the sector boundaries backward jumps are possible trc0.getClusterReference(clRefs, ic0, clSect0, clRow0, clIdx0); - for (int ic1 = ic1Start; ic1 < trc1.getNClusterReferences(); ic1++) { // outside -> inside + for (int ic1 = ic1Start; ic1 < trc1.getNClusterReferences(); ic1++) { // outside -> inside, but on the sector boundaries backward jumps are possible trc1.getClusterReference(clRefs, ic1, clSect1, clRow1, clIdx1); if (clRow1 > clRow0) { ic1Start = ic1 + 1; @@ -391,6 +360,8 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) } } }; + tpcOccAftV.resize(mNOccBinsDrift); + tpcOccBefV.resize(mNOccBinsDrift); for (int iv = 0; iv < nv; iv++) { LOGP(debug, "processing PV {} of {}", iv, nv); @@ -451,11 +422,11 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) } bool ambig = vid.isAmbiguous(); auto trc = recoData.getTrackParam(vid); - if (abs(trc.getEta()) > mMaxEta) { + if (fabs(trc.getEta()) > mMaxEta) { continue; } if (iv < nv - 1 && is == GTrackID::TPC && tpcTr && !tpcTr->hasBothSidesClusters()) { // for unconstrained TPC tracks correct track Z - float corz = vdrit * (tpcTr->getTime0() * mTPCTBinMUS - pvvec[iv].getTimeStamp().getTimeStamp()); + float corz = vdrift * (tpcTr->getTime0() * mTPCTBinMUS - pvvec[iv].getTimeStamp().getTimeStamp()); if (tpcTr->hasASideClustersOnly()) { corz = -corz; // A-side } @@ -487,6 +458,7 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) auto& trcExt = trcExtVec.emplace_back(); recoData.getTrackTime(vid, trcExt.ttime, trcExt.ttimeE); trcExt.track = trc; + trcExt.hashIU = trc.hash(); trcExt.dca = dca; trcExt.gid = vid; trcExt.xmin = xmin; @@ -494,13 +466,19 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) if (tpcTr) { float tsuse = trcExt.ttime / (8 * o2::constants::lhc::LHCBunchSpacingMUS); + if (tpcTr->hasASideClusters()) { + trcExt.setTPCA(); + } + if (tpcTr->hasCSideClusters()) { + trcExt.setTPCC(); + } if (is == GTrackID::TPC) { trcExt.dcaTPC = dca; tsuse = -1e9; } else { o2::track::TrackParCov tmpTPC(*tpcTr); if (iv < nv - 1 && is == GTrackID::TPC && tpcTr && !tpcTr->hasBothSidesClusters()) { // for unconstrained TPC tracks correct track Z - float corz = vdrit * (tpcTr->getTime0() * mTPCTBinMUS - pvvec[iv].getTimeStamp().getTimeStamp()); + float corz = vdrift * (tpcTr->getTime0() * mTPCTBinMUS - pvvec[iv].getTimeStamp().getTimeStamp()); if (tpcTr->hasASideClustersOnly()) { corz = -corz; // A-side } @@ -511,6 +489,7 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) } } fillTPCClInfo(*tpcTr, trcExt, tsuse); + trcExt.chi2TPC = tpcTr->getChi2(); } auto gidRefs = recoData.getSingleDetectorRefs(vid); if (gidRefs[GTrackID::ITS].isIndexSet()) { @@ -554,10 +533,35 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) int tb = pveVec[iv].getTimeStamp().getTimeStamp() * mTPCTBinMUSInv * mNTPCOccBinLengthInv; tpcOccBef = tb < 0 ? mTBinClOccBef[0] : (tb >= mTBinClOccBef.size() ? mTBinClOccBef.back() : mTBinClOccBef[tb]); tpcOccAft = tb < 0 ? mTBinClOccAft[0] : (tb >= mTBinClOccAft.size() ? mTBinClOccAft.back() : mTBinClOccAft[tb]); + int tbc = pveVec[iv].getTimeStamp().getTimeStamp() * mTPCTBinMUSInv * mNTPCOccBinLengthInv - groupOcc / 2.; + for (int iob = 0; iob < mNOccBinsDrift; iob++) { + float sm = 0; + for (int ig = 0; ig < groupOcc; ig++) { + int ocb = tbc + ig + groupOcc * iob; + if (ocb < 0 || ocb >= (int)mMltHistTB.size()) { + sm = -1; + break; + } + sm += mMltHistTB[ocb]; + } + tpcOccAftV[iob] = sm; + // + sm = 0; + for (int ig = 0; ig < groupOcc; ig++) { + int ocb = tbc + ig - groupOcc * iob; + if (ocb < 0 || ocb >= (int)mMltHistTB.size()) { + sm = -1; + break; + } + sm += mMltHistTB[ocb]; + } + tpcOccBefV[iob] = sm; + } } (*mDBGOut) << "trpv" << "orbit=" << recoData.startIR.orbit << "tfID=" << TFCount << "tpcOccBef=" << tpcOccBef << "tpcOccAft=" << tpcOccAft + << "tpcOccBefV=" << tpcOccBefV << "tpcOccAftV=" << tpcOccAftV << "pve=" << pveVec[iv] << "trc=" << trcExtVec << "\n"; if (mDoPairsCorr) { @@ -699,9 +703,6 @@ void TrackingStudySpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) { return; } - if (mTPCCorrMapsLoader.accountCCDBInputs(matcher, obj)) { - return; - } if (matcher == ConcreteDataMatcher("GLO", "MEANVERTEX", 0)) { LOG(info) << "Imposing new MeanVertex: " << ((const o2::dataformats::MeanVertexObject*)obj)->asString(); mMeanVtx = *(const o2::dataformats::MeanVertexObject*)obj; @@ -721,7 +722,7 @@ float TrackingStudySpec::getDCAZCut(float pt) const return fun.Eval(pt); } -DataProcessorSpec getTrackingStudySpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool useMC, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts) +DataProcessorSpec getTrackingStudySpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool useMC) { std::vector outputs; auto dataRequest = std::make_shared(); @@ -752,16 +753,17 @@ DataProcessorSpec getTrackingStudySpec(GTrackID::mask_t srcTracks, GTrackID::mas {"with-its-only", VariantType::Bool, false, {"Store tracks with ITS only"}}, {"pair-correlations", VariantType::Bool, false, {"Do pairs correlation"}}, {"occ-weight-fun", VariantType::String, "(x>=-40&&x<-5) ? (1./1225*pow(x+40,2)) : ((x>-5&&x<15) ? 1. : ((x>=15&&x<40) ? (-0.4/25*x+1.24 ) : ( (x>40&&x<100) ? -0.4/60*x+0.6+0.8/3 : 0)))", {"Occupancy weighting f-n vs time in musec"}}, + {"noccbins", VariantType::Int, 10, {"Number of occupancy bins per full drift time"}}, {"min-x-prop", VariantType::Float, 100.f, {"track should be propagated to this X at least"}}, }; o2::tpc::VDriftHelper::requestCCDBInputs(dataRequest->inputs); - o2::tpc::CorrectionMapsLoader::requestCCDBInputs(dataRequest->inputs, opts, sclOpts); + dataRequest->inputs.emplace_back("corrMap", o2::header::gDataOriginTPC, "TPCCORRMAP", 0, Lifetime::Timeframe); return DataProcessorSpec{ "track-study", dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, srcTracks, useMC, sclOpts)}, + AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, srcTracks, useMC)}, opts}; } diff --git a/Detectors/GlobalTrackingWorkflow/study/src/check-resid-workflow.cxx b/Detectors/GlobalTrackingWorkflow/study/src/check-resid-workflow.cxx new file mode 100644 index 0000000000000..0791d72474ad3 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/src/check-resid-workflow.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 "GlobalTrackingStudy/CheckResidSpec.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "Framework/CallbacksPolicy.h" +#include "DetectorsBase/DPLWorkflowUtils.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" + +using namespace o2::framework; +using GID = o2::dataformats::GlobalTrackID; +using DetID = o2::detectors::DetID; + +// ------------------------------------------------------------------ +void customize(std::vector& policies) +{ + o2::raw::HBFUtilsInitializer::addNewTimeSliceCallback(policies); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector& workflowOptions) +{ + // option allowing to set parameters + std::vector options{ + {"draw-external-only", VariantType::Bool, false, {"just draw content of comma-separated list of histomanagers from checkresid.ext_hm_list"}}, + {"postproc-external-only", VariantType::Bool, false, {"just post-process raw content of comma-separated list of histomanagers from checkresid.ext_hm_list"}}, + {"track-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of track sources to use"}}, + {"cluster-sources", VariantType::String, "ITS", {"comma-separated list of cluster sources to use"}}, + {"disable-root-input", VariantType::Bool, false, {"disable root-files input reader"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + + o2::itsmft::DPLAlpideParamInitializer::addITSConfigOption(options); + o2::raw::HBFUtilsInitializer::addConfigOption(options); + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + + bool drawOnly = configcontext.options().get("draw-external-only"); + bool postProcOnly = configcontext.options().get("postproc-external-only"); + GID::mask_t allowedSourcesTrc = GID::getSourcesMask("ITS,TPC,ITS-TPC,ITS-TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD-TOF"); + GID::mask_t allowedSourcesClus = GID::getSourcesMask("ITS"); + + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); + + GID::mask_t srcTrc = allowedSourcesTrc & GID::getSourcesMask(configcontext.options().get("track-sources")); + GID::mask_t srcCls = allowedSourcesClus & GID::getSourcesMask(configcontext.options().get("cluster-sources")); + + if (!drawOnly) { + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcCls, srcTrc, srcTrc, false); + o2::globaltracking::InputHelper::addInputSpecsPVertex(configcontext, specs, false); // P-vertex is always needed + } else { + allowedSourcesTrc = {}; + allowedSourcesClus = {}; + } + specs.emplace_back(o2::checkresid::getCheckResidSpec(srcTrc, srcCls, drawOnly, postProcOnly)); + + // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit + if (!drawOnly) { + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + } + + return std::move(specs); +} diff --git a/Detectors/GlobalTrackingWorkflow/study/src/its-offset-study-workflow.cxx b/Detectors/GlobalTrackingWorkflow/study/src/its-offset-study-workflow.cxx index 9638312e13f78..5d89ba9b7eabf 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/its-offset-study-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/its-offset-study-workflow.cxx @@ -20,6 +20,7 @@ #include "DetectorsBase/DPLWorkflowUtils.h" #include "GlobalTrackingWorkflowHelpers/InputHelper.h" #include "DetectorsRaw/HBFUtilsInitializer.h" +#include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" using namespace o2::framework; using GID = o2::dataformats::GlobalTrackID; @@ -39,6 +40,7 @@ void customize(std::vector& workflowOptions) {"track-sources", VariantType::String, std::string{"ITS,ITS-TPC-TRD-TOF,ITS-TPC-TOF,ITS-TPC,ITS-TPC-TRD"}, {"comma-separated list of track sources to use"}}, {"disable-root-input", VariantType::Bool, false, {"disable root-files input reader"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + o2::itsmft::DPLAlpideParamInitializer::addITSConfigOption(options); o2::raw::HBFUtilsInitializer::addConfigOption(options, "o2_tfidinfo.root"); std::swap(workflowOptions, options); } diff --git a/Detectors/GlobalTrackingWorkflow/study/src/tpc-track-study-workflow.cxx b/Detectors/GlobalTrackingWorkflow/study/src/tpc-track-study-workflow.cxx index 3e92178c81b7d..e255295d7665f 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/tpc-track-study-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/tpc-track-study-workflow.cxx @@ -20,7 +20,7 @@ #include "DetectorsBase/DPLWorkflowUtils.h" #include "GlobalTrackingWorkflowHelpers/InputHelper.h" #include "DetectorsRaw/HBFUtilsInitializer.h" -#include "TPCCalibration/CorrectionMapsLoader.h" +#include "TPCCalibration/CorrectionMapsOptions.h" #include "TPCWorkflow/TPCScalerSpec.h" using namespace o2::framework; @@ -43,7 +43,7 @@ void customize(std::vector& workflowOptions) {"cluster-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of cluster sources to use"}}, {"disable-root-input", VariantType::Bool, false, {"disable root-files input reader"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; - o2::tpc::CorrectionMapsLoader::addGlobalOptions(options); + o2::tpc::CorrectionMapsOptions::addGlobalOptions(options); o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } @@ -62,7 +62,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); auto useMC = !configcontext.options().get("disable-mc"); - auto sclOpt = o2::tpc::CorrectionMapsLoader::parseGlobalOptions(configcontext.options()); + auto sclOpt = o2::tpc::CorrectionMapsOptions::parseGlobalOptions(configcontext.options()); GID::mask_t srcTrc = allowedSourcesTrc & GID::getSourcesMask(configcontext.options().get("track-sources")); GID::mask_t srcCls = allowedSourcesClus & GID::getSourcesMask(configcontext.options().get("cluster-sources")); if (sclOpt.requestCTPLumi) { @@ -71,10 +71,10 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) } o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcCls, srcTrc, srcTrc, useMC); o2::globaltracking::InputHelper::addInputSpecsPVertex(configcontext, specs, useMC); // P-vertex is always needed - if (sclOpt.needTPCScalersWorkflow() && !configcontext.options().get("disable-root-input")) { - specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt.lumiType == 2, sclOpt.enableMShapeCorrection)); + if (!configcontext.options().get("disable-root-input")) { + specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt.lumiType == o2::tpc::LumiScaleType::TPCScaler, sclOpt.enableMShapeCorrection, sclOpt)); } - specs.emplace_back(o2::trackstudy::getTPCTrackStudySpec(srcTrc, srcCls, useMC, sclOpt)); + specs.emplace_back(o2::trackstudy::getTPCTrackStudySpec(srcTrc, srcCls, 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); diff --git a/Detectors/GlobalTrackingWorkflow/study/src/trackMCStudy-workflow.cxx b/Detectors/GlobalTrackingWorkflow/study/src/trackMCStudy-workflow.cxx index 7aa53e2190a9e..50cc768bdc98d 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/trackMCStudy-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/trackMCStudy-workflow.cxx @@ -19,9 +19,10 @@ #include "Framework/CallbacksPolicy.h" #include "DetectorsBase/DPLWorkflowUtils.h" #include "GlobalTrackingWorkflowHelpers/InputHelper.h" -#include "TPCCalibration/CorrectionMapsLoader.h" +#include "TPCCalibration/CorrectionMapsOptions.h" #include "TPCWorkflow/TPCScalerSpec.h" #include "DetectorsRaw/HBFUtilsInitializer.h" +#include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" using namespace o2::framework; using GID = o2::dataformats::GlobalTrackID; @@ -44,7 +45,8 @@ void customize(std::vector& workflowOptions) {"ignore-sv-check", VariantType::Bool, false, {"disable check for SV combinatorics"}}, {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation, never use it"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; - o2::tpc::CorrectionMapsLoader::addGlobalOptions(options); + o2::itsmft::DPLAlpideParamInitializer::addITSConfigOption(options); + o2::tpc::CorrectionMapsOptions::addGlobalOptions(options); o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } @@ -61,7 +63,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) if (!useMC) { throw std::runtime_error("MC cannot be disabled for this workflow"); } - auto sclOpt = o2::tpc::CorrectionMapsLoader::parseGlobalOptions(configcontext.options()); + auto sclOpt = o2::tpc::CorrectionMapsOptions::parseGlobalOptions(configcontext.options()); GID::mask_t allowedSourcesTrc = GID::getSourcesMask("ITS,TPC,ITS-TPC,TPC-TOF,TPC-TRD,ITS-TPC-TRD,TPC-TRD-TOF,ITS-TPC-TOF,ITS-TPC-TRD-TOF"); GID::mask_t allowedSourcesClus = GID::getSourcesMask("ITS,TPC"); @@ -80,11 +82,11 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) if (checkSV) { o2::globaltracking::InputHelper::addInputSpecsSVertex(configcontext, specs); } - if (sclOpt.needTPCScalersWorkflow() && !configcontext.options().get("disable-root-input")) { - specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt.lumiType == 2, sclOpt.enableMShapeCorrection)); + if (!configcontext.options().get("disable-root-input")) { + specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt.lumiType == o2::tpc::LumiScaleType::TPCScaler, sclOpt.enableMShapeCorrection, sclOpt)); } - specs.emplace_back(o2::trackstudy::getTrackMCStudySpec(srcTrc, srcCls, sclOpt, checkSV)); + specs.emplace_back(o2::trackstudy::getTrackMCStudySpec(srcTrc, srcCls, checkSV)); // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); diff --git a/Detectors/GlobalTrackingWorkflow/study/src/tracking-study-workflow.cxx b/Detectors/GlobalTrackingWorkflow/study/src/tracking-study-workflow.cxx index 413d2e63653fc..fa69d9f2808e0 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/tracking-study-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/tracking-study-workflow.cxx @@ -20,8 +20,9 @@ #include "DetectorsBase/DPLWorkflowUtils.h" #include "GlobalTrackingWorkflowHelpers/InputHelper.h" #include "DetectorsRaw/HBFUtilsInitializer.h" -#include "TPCCalibration/CorrectionMapsLoader.h" +#include "TPCCalibration/CorrectionMapsOptions.h" #include "TPCWorkflow/TPCScalerSpec.h" +#include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" using namespace o2::framework; using GID = o2::dataformats::GlobalTrackID; @@ -43,7 +44,8 @@ void customize(std::vector& workflowOptions) {"cluster-sources", VariantType::String, "TPC,TOF", {"comma-separated list of cluster sources to use"}}, {"disable-root-input", VariantType::Bool, false, {"disable root-files input reader"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; - o2::tpc::CorrectionMapsLoader::addGlobalOptions(options); + o2::itsmft::DPLAlpideParamInitializer::addITSConfigOption(options); + o2::tpc::CorrectionMapsOptions::addGlobalOptions(options); o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } @@ -61,7 +63,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); - auto sclOpt = o2::tpc::CorrectionMapsLoader::parseGlobalOptions(configcontext.options()); + auto sclOpt = o2::tpc::CorrectionMapsOptions::parseGlobalOptions(configcontext.options()); auto useMC = !configcontext.options().get("disable-mc"); GID::mask_t srcTrc = allowedSourcesTrc & GID::getSourcesMask(configcontext.options().get("track-sources")); @@ -69,13 +71,13 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) if (sclOpt.requestCTPLumi) { srcCls = srcCls | GID::getSourcesMask("CTP"); } - if (sclOpt.needTPCScalersWorkflow() && !configcontext.options().get("disable-root-input")) { - specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt.lumiType == 2, sclOpt.enableMShapeCorrection)); + if (!configcontext.options().get("disable-root-input")) { + specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt.lumiType == o2::tpc::LumiScaleType::TPCScaler, sclOpt.enableMShapeCorrection, sclOpt)); } o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcCls, srcTrc, srcTrc, useMC); o2::globaltracking::InputHelper::addInputSpecsPVertex(configcontext, specs, useMC); // P-vertex is always needed - specs.emplace_back(o2::trackstudy::getTrackingStudySpec(srcTrc, srcCls, useMC, sclOpt)); + specs.emplace_back(o2::trackstudy::getTrackingStudySpec(srcTrc, srcCls, 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); diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/RecoWorkflowSpec.cxx b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/RecoWorkflowSpec.cxx deleted file mode 100644 index ab4f90464b31b..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/RecoWorkflowSpec.cxx +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "TOFWorkflow/RecoWorkflowSpec.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 "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 "DetectorsBase/GRPGeomHelper.h" -#include "CommonUtils/NameConf.h" -#include -#include "TStopwatch.h" -#include "TPCCalibration/VDriftHelper.h" - -// from FIT -#include "DataFormatsFT0/RecPoints.h" - -#include // for make_shared, make_unique, unique_ptr -#include - -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 TOFDPLRecoWorkflowTask -{ - using evIdx = o2::dataformats::EvIndex; - using MatchOutputType = std::vector; - - bool mUseMC = true; - bool mUseFIT = false; - - public: - explicit TOFDPLRecoWorkflowTask(std::shared_ptr gr, bool useMC, bool useFIT) : mGGCCDBRequest(gr), mUseMC(useMC), mUseFIT(useFIT) {} - - void init(framework::InitContext& ic) - { - o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); - mTimer.Stop(); - mTimer.Reset(); - } - - void run(framework::ProcessingContext& pc) - { - mTimer.Start(false); - updateTimeDependentParams(pc); - //>>>---------- attach input data --------------->>> - const auto clustersRO = pc.inputs().get>("tofcluster"); - const auto tracksRO = pc.inputs().get>("globaltrack"); - - 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>("fitrecpoints")); - mMatcher.setFITRecPoints(recPoints); - LOG(info) << "TOF Reco Workflow pulled " << recPoints.size() << " FIT RecPoints"; - } - - // 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 itstpclab; - o2::dataformats::MCTruthContainer toflab; - if (mUseMC) { - const auto toflabel = pc.inputs().get*>("tofclusterlabel"); - itstpclab = pc.inputs().get>("itstpclabel"); - toflab = std::move(*toflabel); - } - - 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 - - //... - // LOG(info) << "TOF CLUSTERER : TRANSFORMED " << digits->size() - // << " DIGITS TO " << mClustersArray.size() << " CLUSTERS"; - - // send matching-info - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MTC_ITSTPC", 0}, mMatcher.getMatchedTrackVector()); - if (mUseMC) { - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MCMATCHTOF", 0}, mMatcher.getMatchedTOFLabelsVector()); - } - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "CALIBDATA", 0}, 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); - } - - void updateTimeDependentParams(ProcessingContext& pc) - { - o2::base::GRPGeomHelper::instance().checkUpdates(pc); - mTPCVDriftHelper.extractCCDBInputs(pc); - static bool initOnceDone = false; - if (!initOnceDone) { // this params need to be queried only once - initOnceDone = true; - // put here init-once stuff - } - // we may have other params which need to be queried regularly - if (mTPCVDriftHelper.isUpdated()) { - LOGP(info, "Updating TPC fast transform map with new VDrift factor of {} wrt reference {} from source {}", - mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, mTPCVDriftHelper.getSourceName()); - mMatcher.setTPCVDrift(mTPCVDriftHelper.getVDriftObject()); - mTPCVDriftHelper.acknowledgeUpdate(); - } - } - - void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) - { - if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { - return; - } - if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) { - return; - } - } - - private: - o2::globaltracking::MatchTOF mMatcher; ///< Cluster finder - std::shared_ptr mGGCCDBRequest; - o2::tpc::VDriftHelper mTPCVDriftHelper{}; - TStopwatch mTimer; -}; - -o2::framework::DataProcessorSpec getTOFRecoWorkflowSpec(bool useMC, bool useFIT) -{ - std::vector inputs; - std::vector outputs; - inputs.emplace_back("tofcluster", o2::header::gDataOriginTOF, "CLUSTERS", 0, Lifetime::Timeframe); - 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("itstpclabel", "GLO", "TPCITS_MC", 0, Lifetime::Timeframe); - } - - if (useFIT) { - inputs.emplace_back("fitrecpoints", o2::header::gDataOriginFT0, "RECPOINTS", 0, Lifetime::Timeframe); - } - auto ggRequest = std::make_shared(false, // orbitResetTime - true, // GRPECS=true - false, // GRPLHCIF - true, // GRPMagField - true, // askMatLUT - o2::base::GRPGeomRequest::Aligned, // geometry - inputs, - true); - o2::tpc::VDriftHelper::requestCCDBInputs(inputs); - - outputs.emplace_back(o2::header::gDataOriginTOF, "MTC_ITSTPC", 0, Lifetime::Timeframe); - if (useMC) { - outputs.emplace_back(o2::header::gDataOriginTOF, "MCMATCHTOF", 0, Lifetime::Timeframe); - } - outputs.emplace_back(o2::header::gDataOriginTOF, "CALIBDATA", 0, Lifetime::Timeframe); - - return DataProcessorSpec{ - "TOFRecoWorkflow", - inputs, - outputs, - AlgorithmSpec{adaptFromTask(ggRequest, useMC, useFIT)}, - Options{ - {"material-lut-path", VariantType::String, "", {"Path of the material LUT file"}}}}; -} - -} // end namespace tof -} // end namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/CMakeLists.txt b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/CMakeLists.txt index c8db0209d4471..09ec6081b06b8 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/CMakeLists.txt +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/CMakeLists.txt @@ -9,6 +9,8 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +# add_compile_options(-O0 -g -fPIC -fno-omit-frame-pointer) + o2_add_library(TPCInterpolationWorkflow SOURCES src/TPCInterpolationSpec.cxx src/TPCResidualWriterSpec.cxx diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCInterpolationSpec.h b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCInterpolationSpec.h index 86064f84d881f..83dbb1bd0f5fe 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCInterpolationSpec.h +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCInterpolationSpec.h @@ -38,7 +38,8 @@ namespace tpc class TPCInterpolationDPL : public Task { public: - TPCInterpolationDPL(std::shared_ptr dr, o2::dataformats::GlobalTrackID::mask_t src, o2::dataformats::GlobalTrackID::mask_t srcMap, std::shared_ptr gr, bool useMC, bool processITSTPConly, bool sendTrackData, bool debugOutput) : mDataRequest(dr), mSources(src), mSourcesMap(srcMap), mGGCCDBRequest(gr), mUseMC(useMC), mProcessITSTPConly(processITSTPConly), mSendTrackData(sendTrackData), mDebugOutput(debugOutput) {} + TPCInterpolationDPL(std::shared_ptr dr, o2::dataformats::GlobalTrackID::mask_t src, o2::dataformats::GlobalTrackID::mask_t srcMap, std::shared_ptr gr, bool useMC, + bool processITSTPConly, bool sendTrackData, bool debugOutput, bool extDetResid) : mDataRequest(dr), mSources(src), mSourcesMap(srcMap), mGGCCDBRequest(gr), mUseMC(useMC), mProcessITSTPConly(processITSTPConly), mSendTrackData(sendTrackData), mDebugOutput(debugOutput), mExtDetResid(extDetResid) {} ~TPCInterpolationDPL() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -58,6 +59,7 @@ class TPCInterpolationDPL : public Task bool mProcessITSTPConly{false}; ///< should also tracks without outer point (ITS-TPC only) be processed? bool mProcessSeeds{false}; ///< process not only most complete track, but also its shorter parts bool mDebugOutput{false}; ///< add more information to the output (track points of ITS, TRD and TOF) + bool mExtDetResid{true}; ///< produce unbinned residuals for external detectors bool mSendTrackData{false}; ///< if true, not only the clusters but also corresponding track data will be sent uint32_t mSlotLength{600u}; ///< the length of one calibration slot required to calculate max number of tracks per TF int mMatCorr{2}; ///< the material correction to be used for track interpolation @@ -65,7 +67,8 @@ class TPCInterpolationDPL : public Task }; /// create a processor spec -framework::DataProcessorSpec getTPCInterpolationSpec(o2::dataformats::GlobalTrackID::mask_t srcCls, o2::dataformats::GlobalTrackID::mask_t srcVtx, o2::dataformats::GlobalTrackID::mask_t srcTrk, o2::dataformats::GlobalTrackID::mask_t srcTrkMap, bool useMC, bool processITSTPConly, bool sendTrackData, bool debugOutput); +framework::DataProcessorSpec getTPCInterpolationSpec(o2::dataformats::GlobalTrackID::mask_t srcCls, o2::dataformats::GlobalTrackID::mask_t srcVtx, o2::dataformats::GlobalTrackID::mask_t srcTrk, + o2::dataformats::GlobalTrackID::mask_t srcTrkMap, bool useMC, bool processITSTPConly, bool sendTrackData, bool debugOutput, bool extDetResid); } // namespace tpc } // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCResidualAggregatorSpec.h b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCResidualAggregatorSpec.h index 4f1705533c965..99f20e390a09a 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCResidualAggregatorSpec.h +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCResidualAggregatorSpec.h @@ -128,8 +128,9 @@ class ResidualAggregatorDevice : public o2::framework::Task updateTimeDependentParams(pc); std::chrono::duration ccdbUpdateTime = std::chrono::high_resolution_clock::now() - runStartTime; - // we always require the unbinned residuals and the associated track references + // we always require the unbinned residuals and the associated detector info and track references auto residualsData = pc.inputs().get>("unbinnedRes"); + auto residualsDataDet = pc.inputs().get>("detinfoRes"); auto trackRefs = pc.inputs().get>("trackRefs"); // track data input is optional @@ -145,14 +146,13 @@ class ResidualAggregatorDevice : public o2::framework::Task using lumiDataType = std::decay_t(""))>; std::optional lumiInput; if (mCTPInput) { - recoCont.getCTPLumi(); lumiInput = recoCont.getCTPLumi(); lumi = &lumiInput.value(); } o2::base::TFIDInfoHelper::fillTFIDInfo(pc, mAggregator->getCurrentTFInfo()); LOG(detail) << "Processing TF " << mAggregator->getCurrentTFInfo().tfCounter << " with " << trkData->size() << " tracks and " << residualsData.size() << " unbinned residuals associated to them"; - mAggregator->process(residualsData, trackRefs, trkDataPtr, lumi); + mAggregator->process(residualsData, residualsDataDet, trackRefs, trkDataPtr, lumi); std::chrono::duration runDuration = std::chrono::high_resolution_clock::now() - runStartTime; LOGP(debug, "Duration for run method: {} ms. From this taken for time dependent param update: {} ms", std::chrono::duration_cast(runDuration).count(), @@ -223,6 +223,7 @@ DataProcessorSpec getTPCResidualAggregatorSpec(bool trackInput, bool ctpInput, b auto& inputs = dataRequest->inputs; o2::tpc::VDriftHelper::requestCCDBInputs(inputs); inputs.emplace_back("unbinnedRes", "GLO", "UNBINNEDRES"); + inputs.emplace_back("detinfoRes", "GLO", "DETINFORES"); inputs.emplace_back("trackRefs", "GLO", "TRKREFS"); if (trackInput) { inputs.emplace_back("trkData", "GLO", "TRKDATA"); diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCUnbinnedResidualReaderSpec.h b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCUnbinnedResidualReaderSpec.h index 6c40bb355eb21..724151c90576f 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCUnbinnedResidualReaderSpec.h +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCUnbinnedResidualReaderSpec.h @@ -43,6 +43,7 @@ class TPCUnbinnedResidualReader : public o2::framework::Task std::string mInFileName; std::string mInTreeName; std::vector mUnbinnedResid, *mUnbinnedResidPtr = &mUnbinnedResid; + std::vector mDetInfoUnbRes, *mDetInfoUnbResPtr = &mDetInfoUnbRes; std::vector mTrackData, *mTrackDataPtr = &mTrackData; std::vector mTrackDataCompact, *mTrackDataCompactPtr = &mTrackDataCompact; }; diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx index 521a02cabcbee..4f17aec3d49d5 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx @@ -66,11 +66,12 @@ void TPCInterpolationDPL::updateTimeDependentParams(ProcessingContext& pc) initOnceDone = true; // other init-once stuff const auto& param = SpacePointsCalibConfParam::Instance(); + mInterpolation.setSqrtS(o2::base::GRPGeomHelper::instance().getGRPLHCIF()->getSqrtS()); + mInterpolation.setNHBPerTF(o2::base::GRPGeomHelper::getNHBFPerTF()); mInterpolation.init(mSources, mSourcesMap); if (mProcessITSTPConly) { mInterpolation.setProcessITSTPConly(); } - mInterpolation.setSqrtS(o2::base::GRPGeomHelper::instance().getGRPLHCIF()->getSqrtS()); int nTfs = mSlotLength / (o2::base::GRPGeomHelper::getNHBFPerTF() * o2::constants::lhc::LHCOrbitMUS * 1e-6); bool limitTracks = (param.maxTracksPerCalibSlot < 0) ? false : true; int nTracksPerTfMax = (nTfs > 0 && limitTracks) ? param.maxTracksPerCalibSlot / nTfs : -1; @@ -93,6 +94,11 @@ void TPCInterpolationDPL::updateTimeDependentParams(ProcessingContext& pc) mInterpolation.setProcessSeeds(); } o2::its::GeometryTGeo::Instance()->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2GRot) | o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L)); + mInterpolation.setExtDetResid(mExtDetResid); + mInterpolation.setITSClusterDictionary(mITSDict); + if (mDebugOutput) { + mInterpolation.setDumpTrackPoints(); + } } // we may have other params which need to be queried regularly if (mTPCVDriftHelper.isUpdated()) { @@ -103,10 +109,6 @@ void TPCInterpolationDPL::updateTimeDependentParams(ProcessingContext& pc) mInterpolation.setTPCVDrift(mTPCVDriftHelper.getVDriftObject()); mTPCVDriftHelper.acknowledgeUpdate(); } - if (mDebugOutput) { - mInterpolation.setDumpTrackPoints(); - mInterpolation.setITSClusterDictionary(mITSDict); - } } void TPCInterpolationDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) @@ -142,6 +144,7 @@ void TPCInterpolationDPL::run(ProcessingContext& pc) } } pc.outputs().snapshot(Output{"GLO", "UNBINNEDRES", 0}, mInterpolation.getClusterResiduals()); + pc.outputs().snapshot(Output{"GLO", "DETINFORES", 0}, mInterpolation.getClusterResidualsDetInfo()); pc.outputs().snapshot(Output{"GLO", "TRKREFS", 0}, mInterpolation.getTrackDataCompact()); if (mSendTrackData) { pc.outputs().snapshot(Output{"GLO", "TRKDATA", 0}, mInterpolation.getReferenceTracks()); @@ -158,7 +161,7 @@ void TPCInterpolationDPL::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getTPCInterpolationSpec(GTrackID::mask_t srcCls, GTrackID::mask_t srcVtx, GTrackID::mask_t srcTrk, GTrackID::mask_t srcTrkMap, bool useMC, bool processITSTPConly, bool sendTrackData, bool debugOutput) +DataProcessorSpec getTPCInterpolationSpec(GTrackID::mask_t srcCls, GTrackID::mask_t srcVtx, GTrackID::mask_t srcTrk, GTrackID::mask_t srcTrkMap, bool useMC, bool processITSTPConly, bool sendTrackData, bool debugOutput, bool extDetResid) { auto dataRequest = std::make_shared(); std::vector outputs; @@ -187,6 +190,7 @@ DataProcessorSpec getTPCInterpolationSpec(GTrackID::mask_t srcCls, GTrackID::mas } } outputs.emplace_back("GLO", "UNBINNEDRES", 0, Lifetime::Timeframe); + outputs.emplace_back("GLO", "DETINFORES", 0, Lifetime::Timeframe); outputs.emplace_back("GLO", "TRKREFS", 0, Lifetime::Timeframe); if (sendTrackData) { outputs.emplace_back("GLO", "TRKDATA", 0, Lifetime::Timeframe); @@ -199,10 +203,10 @@ DataProcessorSpec getTPCInterpolationSpec(GTrackID::mask_t srcCls, GTrackID::mas "tpc-track-interpolation", dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask(dataRequest, srcTrk, srcTrkMap, ggRequest, useMC, processITSTPConly, sendTrackData, debugOutput)}, + AlgorithmSpec{adaptFromTask(dataRequest, srcTrk, srcTrkMap, ggRequest, useMC, processITSTPConly, sendTrackData, debugOutput, extDetResid)}, Options{ {"matCorrType", VariantType::Int, 2, {"material correction type (definition in Propagator.h)"}}, - {"sec-per-slot", VariantType::UInt32, 600u, {"number of seconds per calibration time slot (put 0 for infinite slot length)"}}, + {"sec-per-slot", VariantType::UInt32, 300u, {"number of seconds per calibration time slot (put 0 for infinite slot length)"}}, {"process-seeds", VariantType::Bool, false, {"do not remove duplicates, e.g. for ITS-TPC-TRD track also process its seeding ITS-TPC part"}}}}; } diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCResidualWriterSpec.cxx b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCResidualWriterSpec.cxx index 5f6d7ad7b361c..8b06444bdb9b3 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCResidualWriterSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCResidualWriterSpec.cxx @@ -38,6 +38,7 @@ DataProcessorSpec getTPCResidualWriterSpec(bool writeTrackData, bool debugOutput BranchDefinition>{InputSpec{"tracksUnfiltered", "GLO", "TPCINT_TRK", 0}, "tracksUnfiltered", ((writeUnfiltered && writeTrackData) ? 1 : 0)}, BranchDefinition>{InputSpec{"residualsUnfiltered", "GLO", "TPCINT_RES", 0}, "residualsUnfiltered", (writeUnfiltered ? 1 : 0)}, BranchDefinition>{InputSpec{"residuals", "GLO", "UNBINNEDRES"}, "residuals"}, + BranchDefinition>{InputSpec{"detInfo", "GLO", "DETINFORES"}, "detInfo"}, BranchDefinition>{InputSpec{"trackRefs", "GLO", "TRKREFS"}, "trackRefs"}, BranchDefinition>{InputSpec{"tracks", "GLO", "TRKDATA"}, "tracks", (writeTrackData ? 1 : 0)}, BranchDefinition>{InputSpec{"trackExt", "GLO", "TRKDATAEXT"}, "trackExt", (debugOutput ? 1 : 0)})(); diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCUnbinnedResidualReaderSpec.cxx b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCUnbinnedResidualReaderSpec.cxx index 55da5a5e71e44..c2dae375731a4 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCUnbinnedResidualReaderSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCUnbinnedResidualReaderSpec.cxx @@ -44,6 +44,11 @@ void TPCUnbinnedResidualReader::connectTree() assert(mTreeIn); mTreeIn->SetBranchAddress("residuals", &mUnbinnedResidPtr); mTreeIn->SetBranchAddress("trackRefs", &mTrackDataCompactPtr); + if (mTreeIn->GetBranch("detInfo")) { + mTreeIn->SetBranchAddress("detInfo", &mDetInfoUnbResPtr); + } else { + LOGP(warn, "No detInfo branch found in the unbinned residuals tree, empty vector will be sent"); + } if (mTrackInput) { mTreeIn->SetBranchAddress("tracks", &mTrackDataPtr); } @@ -58,6 +63,7 @@ void TPCUnbinnedResidualReader::run(ProcessingContext& pc) LOG(info) << "Pushing " << mUnbinnedResid.size() << " unbinned residuals at entry " << currEntry; pc.outputs().snapshot(Output{"GLO", "UNBINNEDRES", 0}, mUnbinnedResid); pc.outputs().snapshot(Output{"GLO", "TRKREFS", 0}, mTrackDataCompact); + pc.outputs().snapshot(Output{"GLO", "DETINFORES", 0}, mDetInfoUnbRes); if (mTrackInput) { LOG(info) << "Pushing " << mTrackData.size() << " reference tracks for these residuals"; pc.outputs().snapshot(Output{"GLO", "TRKDATA", 0}, mTrackData); @@ -73,6 +79,7 @@ DataProcessorSpec getUnbinnedTPCResidualsReaderSpec(bool trkInput) { std::vector outputs; outputs.emplace_back("GLO", "UNBINNEDRES", 0, Lifetime::Timeframe); + outputs.emplace_back("GLO", "DETINFORES", 0, Lifetime::Timeframe); outputs.emplace_back("GLO", "TRKREFS", 0, Lifetime::Timeframe); if (trkInput) { outputs.emplace_back("GLO", "TRKDATA", 0, Lifetime::Timeframe); diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-interpolation-workflow.cxx b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-interpolation-workflow.cxx index 0905942c956a4..65a79a8635a49 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-interpolation-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-interpolation-workflow.cxx @@ -19,6 +19,7 @@ #include "GlobalTrackingWorkflowHelpers/InputHelper.h" #include "TPCInterpolationWorkflow/TPCInterpolationSpec.h" #include "TPCInterpolationWorkflow/TPCResidualWriterSpec.h" +#include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" using namespace o2::framework; using GID = o2::dataformats::GlobalTrackID; @@ -42,7 +43,9 @@ void customize(std::vector& workflowOptions) {"tracking-sources-map-extraction", VariantType::String, std::string{GID::ALL}, {"can be subset of \"tracking-sources\""}}, {"send-track-data", VariantType::Bool, false, {"Send also the track information to the aggregator"}}, {"debug-output", VariantType::Bool, false, {"Dump extended tracking information for debugging"}}, + {"skip-ext-det-residuals", VariantType::Bool, false, {"Do not produce residuals for external detectors"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + o2::itsmft::DPLAlpideParamInitializer::addITSConfigOption(options); o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } @@ -104,8 +107,9 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) useMC = false; // force disabling MC as long as it is not implemented auto sendTrackData = configcontext.options().get("send-track-data"); auto debugOutput = configcontext.options().get("debug-output"); + auto extDetResid = !configcontext.options().get("skip-ext-det-residuals"); - specs.emplace_back(o2::tpc::getTPCInterpolationSpec(srcClusters, srcVtx, srcTracks, srcTracksMap, useMC, processITSTPConly, sendTrackData, debugOutput)); + specs.emplace_back(o2::tpc::getTPCInterpolationSpec(srcClusters, srcVtx, srcTracks, srcTracksMap, useMC, processITSTPConly, sendTrackData, debugOutput, extDetResid)); if (!configcontext.options().get("disable-root-output")) { specs.emplace_back(o2::tpc::getTPCResidualWriterSpec(sendTrackData, debugOutput)); } diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-residual-aggregator.cxx b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-residual-aggregator.cxx index a127cf313d0e1..20e37c3bcc3b4 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-residual-aggregator.cxx +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-residual-aggregator.cxx @@ -14,10 +14,17 @@ #include "TPCInterpolationWorkflow/TPCResidualAggregatorSpec.h" #include "TPCInterpolationWorkflow/TPCUnbinnedResidualReaderSpec.h" #include "GlobalTrackingWorkflowHelpers/InputHelper.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "Framework/CallbacksPolicy.h" using namespace o2::framework; using GID = o2::dataformats::GlobalTrackID; +void customize(std::vector& policies) +{ + o2::raw::HBFUtilsInitializer::addNewTimeSliceCallback(policies); +} + // we need to add workflow options before including Framework/runDataProcessing void customize(std::vector& workflowOptions) { @@ -27,6 +34,7 @@ void customize(std::vector& workflowOptions) {"enable-ctp", VariantType::Bool, false, {"Subscribe to lumi info from CTP"}}, {"disable-root-input", VariantType::Bool, false, {"disable root-files input readers"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } @@ -43,7 +51,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) bool writeUnbinnedResiduals = false; bool writeBinnedResiduals = false; bool writeTrackData = false; - auto outputType = configcontext.options().get("output-type"); + auto outputType = configcontext.options().get("output-type"); std::vector outputTypes; size_t pos = 0; while ((pos = outputType.find(",")) != std::string::npos) { @@ -79,5 +87,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, maskClusters, maskNone, maskNone, false); } + // 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/reconstruction/include/HMPIDReconstruction/CTFCoder.h b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/CTFCoder.h index da2461c2759ba..894c11864f061 100644 --- a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/CTFCoder.h +++ b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/CTFCoder.h @@ -32,10 +32,10 @@ namespace o2 namespace hmpid { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::HMP) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::HMP, 1.f, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode data to buffer with CTF diff --git a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawFile.h b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawFile.h deleted file mode 100644 index e92e8375ad0d0..0000000000000 --- a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawFile.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file 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 -#include -#include -#include -#include -#include - -#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 deleted file mode 100644 index d5d82d0f238e9..0000000000000 --- a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawMem.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file 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 -#include -#include -#include -#include -#include - -#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 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/src/HmpidDecodeRawFile.cxx b/Detectors/HMPID/reconstruction/src/HmpidDecodeRawFile.cxx deleted file mode 100644 index df97a4d2101e0..0000000000000 --- a/Detectors/HMPID/reconstruction/src/HmpidDecodeRawFile.cxx +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \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 // 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 deleted file mode 100644 index 5a4f2acbfd97b..0000000000000 --- a/Detectors/HMPID/reconstruction/src/HmpidDecodeRawMem.cxx +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file 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 // 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() << " "< // 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() -{ - mRDHSize = sizeof(o2::header::RAWDataHeader) / 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::RAWDataHeader* hpt = (o2::header::RAWDataHeader*)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/workflow/include/HMPIDWorkflow/DigitReaderSpec.h_notused.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/DigitReaderSpec.h_notused.h deleted file mode 100644 index eea9b134bd911..0000000000000 --- a/Detectors/HMPID/workflow/include/HMPIDWorkflow/DigitReaderSpec.h_notused.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file 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 mFile = nullptr; - - std::vector mDigits, *mPdigits = &mDigits; - - o2::dataformats::MCTruthContainer 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/EntropyDecoderSpec.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyDecoderSpec.h index 8c64f326a6878..d03a30ab905e5 100644 --- a/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyDecoderSpec.h +++ b/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyDecoderSpec.h @@ -24,7 +24,7 @@ namespace hmpid { /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt = "none"); } // namespace hmpid } // namespace o2 diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyEncoderSpec.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyEncoderSpec.h index 2fb9fd301f13b..9c2c4eb5b4fb0 100644 --- a/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyEncoderSpec.h +++ b/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyEncoderSpec.h @@ -24,7 +24,7 @@ namespace hmpid { /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); } // namespace hmpid } // namespace o2 diff --git a/Detectors/HMPID/workflow/src/EntropyDecoderSpec.cxx b/Detectors/HMPID/workflow/src/EntropyDecoderSpec.cxx index aa22979bc305f..9ec05efc846fb 100644 --- a/Detectors/HMPID/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/HMPID/workflow/src/EntropyDecoderSpec.cxx @@ -26,11 +26,10 @@ namespace o2 { namespace hmpid { - class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity); + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -42,7 +41,7 @@ class EntropyDecoderSpec : public o2::framework::Task TStopwatch mTimer; }; -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); @@ -91,7 +90,7 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"triggers"}, "HMP", "INTRECORDS", 0, Lifetime::Timeframe}, @@ -100,17 +99,18 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) std::vector inputs; inputs.emplace_back("ctf_HMP", "HMP", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_HMP", "HMP", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("HMP/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_HMP", "HMP", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("HMP/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ "hmpid-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace hmpid } // namespace o2 diff --git a/Detectors/HMPID/workflow/src/EntropyEncoderSpec.cxx b/Detectors/HMPID/workflow/src/EntropyEncoderSpec.cxx index 95723f42d0fd6..c29c1cee459bc 100644 --- a/Detectors/HMPID/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/HMPID/workflow/src/EntropyEncoderSpec.cxx @@ -27,11 +27,10 @@ namespace o2 { namespace hmpid { - class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR = false); + EntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -44,7 +43,7 @@ class EntropyEncoderSpec : public o2::framework::Task TStopwatch mTimer; }; -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR) { mTimer.Stop(); mTimer.Reset(); @@ -89,12 +88,15 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("triggers", "HMP", "INTRECORDS", 0, Lifetime::Timeframe); inputs.emplace_back("digits", "HMP", "DIGITS", 0, Lifetime::Timeframe); - inputs.emplace_back("ctfdict", "HMP", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("HMP/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "HMP", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("HMP/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -103,13 +105,11 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR) inputs, Outputs{{"HMP", "CTFDATA", 0, Lifetime::Timeframe}, {{"ctfrep"}, "HMP", "CTFENCREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace hmpid } // namespace o2 diff --git a/Detectors/HMPID/workflow/src/entropy-encoder-workflow.cxx b/Detectors/HMPID/workflow/src/entropy-encoder-workflow.cxx index fde5e0183abd6..4a1883233b605 100644 --- a/Detectors/HMPID/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/HMPID/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "none", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -37,6 +38,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::hmpid::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"))); + wf.emplace_back(o2::hmpid::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataReader.cxx b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataReader.cxx index 964f342c58b15..90ed033ed67da 100644 --- a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataReader.cxx +++ b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataReader.cxx @@ -210,7 +210,7 @@ void TestDataReader::run(ProcessingContext& pc) size_t pos = mNowFolderNames[i].find_last_of("/"); - if (pos != string::npos) { + if (pos != std::string::npos) { mRunID = mNowFolderNames[i].substr(pos + 1); } @@ -232,7 +232,7 @@ void TestDataReader::run(ProcessingContext& pc) // Getting the FileID string FileIDS; pos = mDiffFileNames[i][0].find_last_of("/"); - if (pos != string::npos) { + if (pos != std::string::npos) { FileIDS = mDiffFileNames[i][0].substr(pos + 1); } @@ -509,7 +509,6 @@ void TestDataReader::run(ProcessingContext& pc) std::vector TestDataReader::GetFName(std::string folder) { - DIR* dirp; char cstr[folder.size() + 1]; diff --git a/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h b/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h index fcdc978fa64f0..c8ef445e273d3 100644 --- a/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h +++ b/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h @@ -176,7 +176,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo 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; + int getLayer(int index) const final; /// Get chip half barrel, from 0 int getHalfBarrel(int index) const; @@ -216,7 +216,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo return getSymbolicName(getChipIndex(lay, hba, sta, det)); } - /// Get the transformation matrix for a given chip (NOT A SENSOR!!!) 'index' by quering the TGeoManager + /// Get the transformation matrix for a given chip (NOT A SENSOR!!!) 'index' by querying the TGeoManager TGeoHMatrix* getMatrix(int index) const { return o2::base::GeometryManager::getMatrix(getDetID(), index); } 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 @@ -314,7 +314,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo static const char* getITS3PixelArrayPattern(int layer) { return Form("%s%d", getITS3PixelArrayPatternRaw(), layer); }; /// sym name of the layer - static const char* composeSymNameITS(bool isITS3 = false); + static const char* composeSymNameITS(); /// sym name of the layer static const char* composeSymNameLayer(int lr, bool isITS3 = false); @@ -333,13 +333,10 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo /// 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, bool isITS3 = false); - // create matrix for transformation from tracking frame to local one for ITS3 - const Mat3D getT2LMatrixITS3(int isn, float alpha); - TString getMatrixPath(int index) const; /// Get the transformation matrix of the SENSOR (not necessary the same as the chip) - /// for a given chip 'index' by quering the TGeoManager + /// for a given chip 'index' by querying the TGeoManager TGeoHMatrix* extractMatrixSensor(int index) const; // create matrix for transformation from sensor local frame to global one @@ -410,7 +407,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo std::vector mNumberOfChipsPerStave; ///< number of chips per stave std::vector mNumberOfChipsPerHalfBarrel; ///< number of chips per halfbarrel std::vector mNumberOfChipsPerLayer; ///< number of chips per stave - std::vector mLastChipIndex; ///< max ID of the detctor in the layer + std::vector mLastChipIndex; ///< max ID of the detector in the layer std::array mIsLayerITS3; ///< flag with the information of the ITS version (ITS2 or ITS3) std::array mLayerToWrapper; ///< Layer to wrapper correspondence diff --git a/Detectors/ITSMFT/ITS/base/src/GeometryTGeo.cxx b/Detectors/ITSMFT/ITS/base/src/GeometryTGeo.cxx index 89b4d63729543..5dc499d05037e 100644 --- a/Detectors/ITSMFT/ITS/base/src/GeometryTGeo.cxx +++ b/Detectors/ITSMFT/ITS/base/src/GeometryTGeo.cxx @@ -290,14 +290,8 @@ bool GeometryTGeo::getChipId(int index, int& lay, int& hba, int& sta, int& hsta, } //__________________________________________________________________________ -const char* GeometryTGeo::composeSymNameITS(bool isITS3) +const char* GeometryTGeo::composeSymNameITS() { - if (isITS3) { -#ifdef ENABLE_UPGRADES - return o2::detectors::DetID(o2::detectors::DetID::IT3).getName(); -#endif - } - return o2::detectors::DetID(o2::detectors::DetID::ITS).getName(); } @@ -899,19 +893,6 @@ TGeoHMatrix& GeometryTGeo::createT2LMatrix(int isn) return t2l; } -//__________________________________________________________________________ -const o2::math_utils::Transform3D GeometryTGeo::getT2LMatrixITS3(int isn, float alpha) -{ - // create for sensor isn the TGeo matrix for Tracking to Local frame transformations with correction for effective thickness - static TGeoHMatrix t2l; - t2l.Clear(); - t2l.RotateZ(alpha * RadToDeg()); // rotate in direction of normal to the tangent to the cylinder - const TGeoHMatrix& matL2G = getMatrixL2G(isn); - const auto& matL2Gi = matL2G.Inverse(); - t2l.MultiplyLeft(&matL2Gi); - return Mat3D(t2l); -} - //__________________________________________________________________________ int GeometryTGeo::extractVolumeCopy(const char* name, const char* prefix) const { diff --git a/Detectors/ITSMFT/ITS/macros/test/CMakeLists.txt b/Detectors/ITSMFT/ITS/macros/test/CMakeLists.txt index 2ed11fc852c8b..ffdbdf1990a32 100644 --- a/Detectors/ITSMFT/ITS/macros/test/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/macros/test/CMakeLists.txt @@ -113,3 +113,24 @@ o2_add_test_root_macro(CheckDuplicates.C PUBLIC_LINK_LIBRARIES O2::DataFormatsITS O2::DataFormatsITSMFT LABELS its) + +o2_add_test_root_macro(CheckDROF.C + PUBLIC_LINK_LIBRARIES O2::DataFormatsITS + O2::DataFormatsITSMFT + LABELS its) + +o2_add_test_root_macro(CheckStaggering.C + PUBLIC_LINK_LIBRARIES O2::DataFormatsITS + O2::DataFormatsITSMFT + O2::ITSMFTReconstruction + O2::DCAFitter + O2::CCDB + O2::DetectorsVertexing + O2::ReconstructionDataFormats + LABELS its COMPILE_ONLY) + +o2_add_test_root_macro(CheckSeeding.C + PUBLIC_LINK_LIBRARIES O2::DataFormatsITS + O2::SimulationDataFormat + O2::Steer + LABELS its COMPILE_ONLY) diff --git a/Detectors/ITSMFT/ITS/macros/test/CheckDROF.C b/Detectors/ITSMFT/ITS/macros/test/CheckDROF.C new file mode 100644 index 0000000000000..01acd2935981d --- /dev/null +++ b/Detectors/ITSMFT/ITS/macros/test/CheckDROF.C @@ -0,0 +1,1427 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 +#include +#include +#include +#include + +#include +#include +#include +#include "TH1F.h" +#include +#include "TH2D.h" +#include "TH3D.h" +#include +#include +#include +#include +#include +#include + +#include "ITSBase/GeometryTGeo.h" +#include "SimulationDataFormat/MCEventHeader.h" +#include "DetectorsBase/Propagator.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" +#include "DataFormatsITS/Vertex.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "SimulationDataFormat/DigitizationContext.h" + +#endif + +using namespace std; + +void plotHistos(TFile* fWO, TFile* f, const char* append = ""); + +struct ParticleInfo { // particle level information for tracks + int event; + int pdg; + float pt; + float eta; + float phi; + int mother; + int first; + float pvx{}; + float pvy{}; + float pvz{}; + float dcaxy; + float dcaz; + unsigned short clusters = 0u; + unsigned char isReco = 0u; + unsigned char isFake = 0u; + bool isPrimary = false; + int bcInROF{-1}; + int rofId{-1}; + unsigned char storedStatus = 2; /// not stored = 2, fake = 1, good = 0 + o2::its::TrackITS track; + + void print() const + { + LOGP(info, "event={} pdg={} pt={} eta={} phi={} mother={} clusters={:7b} isReco={} isFake={} isPrimary={} bcInROF={} rofId={} | {}", event, pdg, pt, eta, phi, mother, clusters, isReco, isFake, isPrimary, bcInROF, rofId, track.asString()); + } + + int getNClusters() const noexcept + { + int nCl{0}; + for (unsigned int bit{0}; bit < sizeof(ParticleInfo::clusters) * 8; ++bit) { + nCl += bool(clusters & (1 << bit)); + } + return nCl; + } + + bool isReconstructable() const noexcept + { + return isPrimary && (7 == getNClusters()) && bcInROF >= 0; + } +}; +#pragma link C++ class ParticleInfo + ; +#pragma link C++ class std::vector < ParticleInfo> + ; + +struct VertexInfo { // Vertex level info + float purity; // fraction of main cont. labels to all + o2::its::Vertex vertex; // reconstructed vertex + int bcInROF{-1}; + int rofId{-1}; + int event{-1}; // corresponding MC event + std::vector labels; // contributor labels + o2::MCCompLabel mainLabel; // main label + + void computeMain() + { + std::unordered_map freq; + size_t totalSet = 0; + + // Count frequencies of set labels + for (auto const& lab : labels) { + if (lab.isSet()) { + ++freq[lab]; + ++totalSet; + } + } + if (totalSet == 0) { + return; + } + // Find the label with maximum count + auto best = std::max_element(freq.begin(), freq.end(), [](auto const& a, auto const& b) { return a.second < b.second; }); + size_t maxCount = best->second; + + // If there's no majority (all counts == 1), fall back to first set label + o2::MCCompLabel mainLab; + if (maxCount == 1) { + for (auto const& lab : labels) { + if (lab.isSet()) { + mainLab = lab; + break; + } + } + } else { + mainLab = best->first; + } + purity = (float)maxCount / (float)labels.size(); + } +}; +#pragma link C++ class VertexInfo + ; + +using namespace o2::itsmft; +using namespace o2::its; + +void CheckDROF(bool plot = false, bool write = false, const std::string& tracfile = "o2trac_its.root", + const std::string& magfile = "o2sim_grp.root", + const std::string& clusfile = "o2clus_its.root", + const std::string& kinefile = "o2sim_Kine.root") +{ + constexpr int64_t roFrameLengthInBC = 198; // for pp=198 + constexpr int64_t roFrameBiasInBC = 64; // ITS delay accounted for in digitization + constexpr float roFbins{roFrameLengthInBC + 2.f}; + constexpr int bcValStart{60}, bcValEnd{140}; // adjustable region of validation train + + if (!plot) { + int trackID, evID, srcID; + bool fake; + + // Magnetic field and Propagator + o2::base::Propagator::initFieldFromGRP(magfile); + float bz = o2::base::Propagator::Instance()->getNominalBz(); + + // 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); + mcTree->SetBranchStatus("MCEventHeader*", 1); + std::vector* mcArr = nullptr; + mcTree->SetBranchAddress("MCTrack", &mcArr); + o2::dataformats::MCEventHeader* mcEvent = nullptr; + mcTree->SetBranchAddress("MCEventHeader.", &mcEvent); + + auto* dc = o2::steer::DigitizationContext::loadFromFile("collisioncontext.root"); + const auto& irs = dc->getEventRecords(); + dc->printCollisionSummary(false, 20); + + // Clusters + TFile::Open(clusfile.data()); + TTree* clusTree = (TTree*)gFile->Get("o2sim"); + std::vector* clusArr = nullptr; + clusTree->SetBranchAddress("ITSClusterComp", &clusArr); + + // Cluster MC labels + o2::dataformats::MCTruthContainer* clusLabArr = nullptr; + clusTree->SetBranchAddress("ITSClusterMCTruth", &clusLabArr); + + // Reconstructed tracks + TFile* file1 = TFile::Open(tracfile.data()); + TTree* recTree = (TTree*)gFile->Get("o2sim"); + std::vector* recArr = nullptr; + recTree->SetBranchAddress("ITSTrack", &recArr); + // Track MC labels + std::vector* trkLabArr = nullptr; + recTree->SetBranchAddress("ITSTrackMCTruth", &trkLabArr); + std::vector rofRecVec, *rofRecVecP = &rofRecVec; + recTree->SetBranchAddress("ITSTracksROF", &rofRecVecP); + // Vertices + std::vector* recVerArr = nullptr; + recTree->SetBranchAddress("Vertices", &recVerArr); + std::vector* recVerROFArr = nullptr; + recTree->SetBranchAddress("VerticesROF", &recVerROFArr); + std::vector* recVerLabelsArr = nullptr; + recTree->SetBranchAddress("ITSVertexMCTruth", &recVerLabelsArr); + std::vector* recVerPurityArr = nullptr; + recTree->SetBranchAddress("ITSVertexMCPurity", &recVerPurityArr); + + std::cout << "** Filling particle table ... " << std::flush; + int lastEventIDcl = -1, cf = 0; + const int nev = mcTree->GetEntriesFast(); + std::vector> info; + info.resize(nev); + TH1D* hZvertex = new TH1D("hZvertex", "Z vertex", 100, -20, 20); + for (int n = 0; n < nev; n++) { // loop over MC events + mcTree->GetEvent(n); + info[n].resize(mcArr->size()); + hZvertex->Fill(mcEvent->GetZ()); + const auto& ir = irs[mcEvent->GetEventID() - 1]; // event id start from 1 + 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].pvx = mcEvent->GetX(); + info[n][mcI].pvy = mcEvent->GetY(); + info[n][mcI].pvz = mcEvent->GetZ(); + info[n][mcI].pt = part.GetPt(); + info[n][mcI].phi = part.GetPhi(); + info[n][mcI].eta = part.GetEta(); + info[n][mcI].isPrimary = part.isPrimary(); + if (!ir.isDummy()) { + info[n][mcI].bcInROF = (ir.toLong() - roFrameBiasInBC) % roFrameLengthInBC; + info[n][mcI].rofId = (ir.toLong() - roFrameBiasInBC) / roFrameLengthInBC; + } + } + } + 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}, length{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; + } + 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].track = recArr->at(iTrack); + info[evID][trackID].storedStatus = fake; + static float ip[2]{0., 0.}; + info[evID][trackID].track.getImpactParams(info[evID][trackID].pvx, info[evID][trackID].pvy, info[evID][trackID].pvz, bz, ip); + info[evID][trackID].dcaxy = ip[0]; + info[evID][trackID].dcaz = ip[1]; + } + + fakes += fake; + good += !fake; + if (!fake) { + for (unsigned int bit{0}; bit < 7; ++bit) { + length += bool(info[evID][trackID].clusters & (1 << bit)); + } + } + } + } + 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; + std::cout << "\t- Average length of good tracks: " << (double)length / (double)good << std::endl; + + TFile* fOut{nullptr}; + if (write) { + fOut = TFile::Open("checkDROF.root", "RECREATE"); + } + + const 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); + } + + ////////////////////// + // Eff Tracks + { + auto num = new TH2D("num", ";#it{p}_{T} (GeV/#it{c});NCls;Efficiency (fake-track rate)", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + num->Sumw2(); + auto fak = new TH2D("fak", ";#it{p}_{T} (GeV/#it{c});NCls;Fak", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + fak->Sumw2(); + auto multiFak = new TH2D("multiFak", ";#it{p}_{T} (GeV/#it{c});NCls;Fak", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + multiFak->Sumw2(); + auto clone = new TH2D("clone", ";#it{p}_{T} (GeV/#it{c});NCls;Clone", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + clone->Sumw2(); + auto den = new TH2D("den", ";#it{p}_{T} (GeV/#it{c});NCls;Den", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + den->Sumw2(); + auto numMC = new TH2D("numMC", ";#it{p}_{T,MC} (GeV/#it{c});NCls;Efficiency (fake-track rate)", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + numMC->Sumw2(); + auto fakMC = new TH2D("fakMC", ";#it{p}_{T,MC} (GeV/#it{c});NCls;Fak", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + fakMC->Sumw2(); + auto multiFakMC = new TH2D("multiFakMC", ";#it{p}_{T,MC} (GeV/#it{c});NCls;Fak", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + multiFakMC->Sumw2(); + auto cloneMC = new TH2D("cloneMC", ";#it{p}_{T,MC} (GeV/#it{c});NCls;Clone", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + cloneMC->Sumw2(); + auto denMC = new TH2D("denMC", ";#it{p}_{T,MC} (GeV/#it{c});NCls;Den", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + denMC->Sumw2(); + + auto numVal = new TH2D("numVal", ";#it{p}_{T} (GeV/#it{c});NCls;Efficiency (fake-track rate)", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + numVal->Sumw2(); + auto fakVal = new TH2D("fakVal", ";#it{p}_{T} (GeV/#it{c});NCls;Fak", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + fakVal->Sumw2(); + auto multiFakVal = new TH2D("multiFakVal", ";#it{p}_{T} (GeV/#it{c});NCls;Fak", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + multiFakVal->Sumw2(); + auto cloneVal = new TH2D("cloneVal", ";#it{p}_{T} (GeV/#it{c});NCls;Clone", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + cloneVal->Sumw2(); + auto denVal = new TH2D("denVal", ";#it{p}_{T} (GeV/#it{c});NCls;Den", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + denVal->Sumw2(); + auto numMCVal = new TH2D("numMCVal", ";#it{p}_{T,MC} (GeV/#it{c});NCls;Efficiency (fake-track rate)", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + numMCVal->Sumw2(); + auto fakMCVal = new TH2D("fakMCVal", ";#it{p}_{T,MC} (GeV/#it{c});NCls;Fak", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + fakMCVal->Sumw2(); + auto multiFakMCVal = new TH2D("multiFakMCVal", ";#it{p}_{T,MC} (GeV/#it{c});NCls;Fak", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + multiFakMCVal->Sumw2(); + auto cloneMCVal = new TH2D("cloneMCVal", ";#it{p}_{T,MC} (GeV/#it{c});NCls;Clone", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + cloneMCVal->Sumw2(); + auto denMCVal = new TH2D("denMCVal", ";#it{p}_{T,MC} (GeV/#it{c});NCls;Den", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + denMCVal->Sumw2(); + + auto numMig = new TH2D("numMig", ";#it{p}_{T} (GeV/#it{c});NCls;Efficiency (fake-track rate)", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + numMig->Sumw2(); + auto fakMig = new TH2D("fakMig", ";#it{p}_{T} (GeV/#it{c});NCls;Fak", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + fakMig->Sumw2(); + auto multiFakMig = new TH2D("multiFakMig", ";#it{p}_{T} (GeV/#it{c});NCls;Fak", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + multiFakMig->Sumw2(); + auto cloneMig = new TH2D("cloneMig", ";#it{p}_{T} (GeV/#it{c});NCls;Clone", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + cloneMig->Sumw2(); + auto denMig = new TH2D("denMig", ";#it{p}_{T} (GeV/#it{c});NCls;Den", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + denMig->Sumw2(); + auto numMCMig = new TH2D("numMCMig", ";#it{p}_{T,MC} (GeV/#it{c});NCls;Efficiency (fake-track rate)", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + numMCMig->Sumw2(); + auto fakMCMig = new TH2D("fakMCMig", ";#it{p}_{T,MC} (GeV/#it{c});NCls;Fak", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + fakMCMig->Sumw2(); + auto multiFakMCMig = new TH2D("multiFakMCMig", ";#it{p}_{T,MC} (GeV/#it{c});NCls;Fak", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + multiFakMCMig->Sumw2(); + auto cloneMCMig = new TH2D("cloneMCMig", ";#it{p}_{T,MC} (GeV/#it{c});NCls;Clone", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + cloneMCMig->Sumw2(); + auto denMCMig = new TH2D("denMCMig", ";#it{p}_{T,MC} (GeV/#it{c});NCls;Den", nb, xbins, 4, 4 - 0.5, 8 - 0.5); + denMCMig->Sumw2(); + + TProfile* avgClsZ = new TProfile("avgClsZ", "good attachment;z_{MC};", 25, -20, 20); + avgClsZ->SetLineColor(kBlack); + TProfile* avgClsZGood = new TProfile("avgClsZGood", "good attachment;z_{MC};", 25, -20, 20); + avgClsZGood->SetLineColor(kBlue); + TProfile* avgClsZFake = new TProfile("avgClsZFake", "fake attachment;z_{MC};", 25, -20, 20); + avgClsZFake->SetLineColor(kRed); + + for (auto& evInfo : info) { + for (auto& part : evInfo) { + if (!part.isReconstructable()) { + continue; + } + den->Fill(part.track.getPt(), part.track.getNClusters()); + denMC->Fill(part.pt, part.track.getNClusters()); + if (part.isReco) { + num->Fill(part.track.getPt(), part.track.getNClusters()); + numMC->Fill(part.pt, part.track.getNClusters()); + if (part.isReco > 1) { + for (int _i{0}; _i < part.isReco - 1; ++_i) { + clone->Fill(part.track.getPt(), part.track.getNClusters()); + cloneMC->Fill(part.pt, part.track.getNClusters()); + } + } + } + if (part.isFake) { + fak->Fill(part.track.getPt(), part.track.getNClusters()); + fakMC->Fill(part.pt, part.track.getNClusters()); + if (part.isFake > 1) { + for (int _i{0}; _i < part.isFake - 1; ++_i) { + multiFak->Fill(part.track.getPt(), part.track.getNClusters()); + multiFakMC->Fill(part.pt, part.track.getNClusters()); + } + } + } + + // sep into validation and migration region + if (bcValStart < part.bcInROF && part.bcInROF < bcValEnd) { + denVal->Fill(part.track.getPt(), part.track.getNClusters()); + denMCVal->Fill(part.pt, part.track.getNClusters()); + if (part.isReco) { + numVal->Fill(part.track.getPt(), part.track.getNClusters()); + numMCVal->Fill(part.pt, part.track.getNClusters()); + if (part.isReco > 1) { + for (int _i{0}; _i < part.isReco - 1; ++_i) { + cloneVal->Fill(part.track.getPt(), part.track.getNClusters()); + cloneMCVal->Fill(part.pt, part.track.getNClusters()); + } + } + } + if (part.isFake) { + fakVal->Fill(part.track.getPt(), part.track.getNClusters()); + fakMCVal->Fill(part.pt, part.track.getNClusters()); + if (part.isFake > 1) { + for (int _i{0}; _i < part.isFake - 1; ++_i) { + multiFakVal->Fill(part.track.getPt(), part.track.getNClusters()); + multiFakMCVal->Fill(part.pt, part.track.getNClusters()); + } + } + } + } else { + denMig->Fill(part.track.getPt(), part.track.getNClusters()); + denMCMig->Fill(part.pt, part.track.getNClusters()); + if (part.isReco) { + numMig->Fill(part.track.getPt(), part.track.getNClusters()); + numMCMig->Fill(part.pt, part.track.getNClusters()); + if (part.isReco > 1) { + for (int _i{0}; _i < part.isReco - 1; ++_i) { + cloneMig->Fill(part.track.getPt(), part.track.getNClusters()); + cloneMCMig->Fill(part.pt, part.track.getNClusters()); + } + } + } + if (part.isFake) { + fakMig->Fill(part.track.getPt(), part.track.getNClusters()); + fakMCMig->Fill(part.pt, part.track.getNClusters()); + if (part.isFake > 1) { + for (int _i{0}; _i < part.isFake - 1; ++_i) { + multiFakMig->Fill(part.track.getPt(), part.track.getNClusters()); + multiFakMCMig->Fill(part.pt, part.track.getNClusters()); + } + } + } + } + + int nCl = part.getNClusters(); + avgClsZ->Fill(part.pvz, nCl); + if (part.isReco) { + avgClsZGood->Fill(part.pvz, nCl); + } + if (part.isFake) { + avgClsZFake->Fill(part.pvz, nCl); + } + } + } + + auto sum = (TH2D*)num->Clone("sum"); + auto sumMC = (TH2D*)numMC->Clone("sumMC"); + sum->Add(fak); + sumMC->Add(fakMC); + sum->SetLineColor(kBlack); + sumMC->SetLineColor(kBlack); + fak->SetLineColor(2); + fakMC->SetLineColor(2); + multiFak->SetLineColor(kRed + 1); + multiFakMC->SetLineColor(kRed + 1); + + auto sumVal = (TH2D*)numVal->Clone("sumVal"); + auto sumMCVal = (TH2D*)numMCVal->Clone("sumMCVal"); + sumVal->Add(fakVal); + sumMCVal->Add(fakMCVal); + sumVal->SetLineColor(kBlack); + sumMCVal->SetLineColor(kBlack); + fakVal->SetLineColor(2); + fakMCVal->SetLineColor(2); + multiFakVal->SetLineColor(kRed + 1); + multiFakMCVal->SetLineColor(kRed + 1); + + auto sumMig = (TH2D*)numMig->Clone("sumMig"); + auto sumMCMig = (TH2D*)numMCMig->Clone("sumMCMig"); + sumMig->Add(fakMig); + sumMCMig->Add(fakMCMig); + sumMig->SetLineColor(kBlack); + sumMCMig->SetLineColor(kBlack); + fakMig->SetLineColor(2); + fakMCMig->SetLineColor(2); + multiFakMig->SetLineColor(kRed + 1); + multiFakMCMig->SetLineColor(kRed + 1); + + if (write) { + num->Write(); + den->Write(); + sum->Write(); + fak->Write(); + multiFak->Write(); + numMC->Write(); + denMC->Write(); + sumMC->Write(); + fakMC->Write(); + multiFakMC->Write(); + + numVal->Write(); + denVal->Write(); + sumVal->Write(); + fakVal->Write(); + multiFakVal->Write(); + numMCVal->Write(); + denMCVal->Write(); + sumMCVal->Write(); + fakMCVal->Write(); + multiFakMCVal->Write(); + + numMig->Write(); + denMig->Write(); + sumMig->Write(); + fakMig->Write(); + multiFakMig->Write(); + numMCMig->Write(); + denMCMig->Write(); + sumMCMig->Write(); + fakMCMig->Write(); + multiFakMCMig->Write(); + } else { + TCanvas* c1 = new TCanvas; + c1->SetLogx(); + c1->SetGrid(); + gPad->DrawFrame(ptcutl, 0.05, ptcuth, 1.03, ";#it{p}_{T} (GeV/#it{c});Efficiency (fake-track rate)"); + + auto denp = den->ProjectionX(); + auto nump = num->ProjectionX(); + auto fakp = fak->ProjectionX(); + auto multiFakp = multiFak->ProjectionX(); + auto sump = sum->ProjectionX(); + auto clonep = clone->ProjectionX(); + + sump->Divide(sump, denp, 1, 1, "B"); + sump->Draw("hist;same"); + nump->Divide(nump, denp, 1, 1, "B"); + nump->Draw("hist;same"); + fakp->Divide(fakp, denp, 1, 1, "B"); + fakp->Draw("hist;same"); + multiFakp->Divide(multiFakp, denp, 1, 1, "B"); + multiFakp->Draw("hist;same"); + clonep->Divide(clonep, denp, 1, 1, "B"); + clonep->SetLineColor(3); + clonep->Draw("hist;same"); + + TCanvas* c2 = new TCanvas; + c2->Divide(2, 1); + c2->cd(1); + hZvertex->Draw(); + c2->cd(2); + avgClsZ->Draw(); + avgClsZGood->Draw("same"); + avgClsZFake->Draw("same"); + } + } + + ////////////////////// + // DROF Tracks + { + auto hBC = new TH1F("hBC", "Distance in BC;bcInROF;counts.", roFbins, -0.5, roFbins - 0.5); + auto hBCTracksDen = new TH2F("hBCTracksDen", "BC Den Tracks;bcInROF;NCls;eff.", roFbins, -0.5, roFbins - 0.5, 4, 4 - 0.5, 8 - 0.5); + auto hBCTracksNum = new TH2F("hBCTracksNum", "BC Num Tracks;bcInROF;NCls;eff.", roFbins, -0.5, roFbins - 0.5, 4, 4 - 0.5, 8 - 0.5); + auto hBCTracksFake = new TH2F("hBCTracksFake", "BC Fake Tracks;bcInROF;NCls;eff.", roFbins, -0.5, roFbins - 0.5, 4, 4 - 0.5, 8 - 0.5); + auto hBCTracksSum = new TH2F("hBCTracksSum", "BC Sum Tracks;bcInROF;NCls;eff.", roFbins, -0.5, roFbins - 0.5, 4, 4 - 0.5, 8 - 0.5); + + // control region + auto hBCTracksDenVal = new TH2F("hBCTracksDenVal", "Val BC Den Tracks;bcInROF;NCls;eff.", roFbins, -0.5, roFbins - 0.5, 4, 4 - 0.5, 8 - 0.5); + auto hBCTracksNumVal = new TH2F("hBCTracksNumVal", "Val BC Num Tracks;bcInROF;NCls;eff.", roFbins, -0.5, roFbins - 0.5, 4, 4 - 0.5, 8 - 0.5); + auto hBCTracksFakeVal = new TH2F("hBCTracksFakeVal", "Val BC Fake Tracks;bcInROF;NCls;eff.", roFbins, -0.5, roFbins - 0.5, 4, 4 - 0.5, 8 - 0.5); + auto hBCTracksSumVal = new TH2F("hBCTracksSumVal", "Val BC Sum Tracks;bcInROF;NCls;eff.", roFbins, -0.5, roFbins - 0.5, 4, 4 - 0.5, 8 - 0.5); + + // migration region + auto hBCTracksDenMig = new TH2F("hBCTracksDenMig", "MigBC Den Tracks;bcInROF;NCls;eff.", roFbins, -0.5, roFbins - 0.5, 4, 4 - 0.5, 8 - 0.5); + auto hBCTracksNumMig = new TH2F("hBCTracksNumMig", "MigBC Num Tracks;bcInROF;NCls;eff.", roFbins, -0.5, roFbins - 0.5, 4, 4 - 0.5, 8 - 0.5); + auto hBCTracksFakeMig = new TH2F("hBCTracksFakeMig", "MigBC Fake Tracks;bcInROF;NCls;eff.", roFbins, -0.5, roFbins - 0.5, 4, 4 - 0.5, 8 - 0.5); + auto hBCTracksSumMig = new TH2F("hBCTracksSumMig", "MigBC Sum Tracks;bcInROF;NCls;eff.", roFbins, -0.5, roFbins - 0.5, 4, 4 - 0.5, 8 - 0.5); + + for (auto& evInfo : info) { + for (auto& part : evInfo) { + if (!part.isReconstructable()) { + continue; + } + hBC->Fill(part.bcInROF); + hBCTracksDen->Fill(part.bcInROF, part.track.getNClusters()); + if (part.isReco) { + hBCTracksNum->Fill(part.bcInROF, part.track.getNClusters()); + } + if (part.isFake) { + hBCTracksFake->Fill(part.bcInROF, part.track.getNClusters()); + } + + if (bcValStart < part.bcInROF && part.bcInROF < bcValEnd) { + hBCTracksDenVal->Fill(part.bcInROF, part.track.getNClusters()); + if (part.isReco) { + hBCTracksNumVal->Fill(part.bcInROF, part.track.getNClusters()); + } + if (part.isFake) { + hBCTracksFakeVal->Fill(part.bcInROF, part.track.getNClusters()); + } + } else { + hBCTracksDenMig->Fill(part.bcInROF, part.track.getNClusters()); + if (part.isReco) { + hBCTracksNumMig->Fill(part.bcInROF, part.track.getNClusters()); + } + if (part.isFake) { + hBCTracksFakeMig->Fill(part.bcInROF, part.track.getNClusters()); + } + } + } + } + + hBCTracksSum->Add(hBCTracksNum); + hBCTracksSum->Add(hBCTracksFake); + hBCTracksSum->SetLineColor(kBlack); + hBCTracksFake->SetLineColor(2); + + hBCTracksSumVal->Add(hBCTracksNum); + hBCTracksSumVal->Add(hBCTracksFake); + hBCTracksSumVal->SetLineColor(kBlack); + hBCTracksFakeVal->SetLineColor(2); + + hBCTracksSumMig->Add(hBCTracksNum); + hBCTracksSumMig->Add(hBCTracksFake); + hBCTracksSumMig->SetLineColor(kBlack); + hBCTracksFakeMig->SetLineColor(2); + + if (write) { + hBCTracksDen->Write(); + hBCTracksNum->Write(); + hBCTracksFake->Write(); + hBCTracksSum->Write(); + + hBCTracksDenVal->Write(); + hBCTracksNumVal->Write(); + hBCTracksFakeVal->Write(); + hBCTracksSumVal->Write(); + + hBCTracksDenMig->Write(); + hBCTracksNumMig->Write(); + hBCTracksFakeMig->Write(); + hBCTracksSumMig->Write(); + } else { + auto hBCTracksDenp = hBCTracksDen->ProjectionX(); + auto hBCTracksSump = hBCTracksSum->ProjectionX(); + auto hBCTracksNump = hBCTracksNum->ProjectionX(); + auto hBCTracksFakep = hBCTracksFake->ProjectionX(); + + hBCTracksSump->Divide(hBCTracksSump, hBCTracksDenp, 1., 1., "B"); + hBCTracksNump->Divide(hBCTracksNump, hBCTracksDenp, 1., 1., "B"); + hBCTracksFakep->Divide(hBCTracksFakep, hBCTracksDenp, 1., 1., "B"); + + auto c = new TCanvas; + c->Divide(2, 1); + c->cd(1); + hBC->Draw(); + c->cd(2); + gPad->DrawFrame(-0.5, 1e-3, roFbins - 0.5, 1.1, "Tracking >4 ITS cls;bcInROF;eff."); + gPad->SetGrid(); + hBCTracksSump->Draw("histe;same"); + hBCTracksNump->Draw("histe;same"); + hBCTracksFakep->Draw("histe;same"); + auto leg = new TLegend; + leg->AddEntry(hBCTracksSump, "Sum"); + leg->AddEntry(hBCTracksNump, "Good"); + leg->AddEntry(hBCTracksFakep, "Fake"); + leg->Draw(); + } + } + + ////////////////////// + // DROF Vertices + if constexpr (false) { + std::vector vertexInfo; + std::cout << "** Creating vertices/particles correspondance ... " << std::flush; + for (int frame = 0; frame < recTree->GetEntriesFast(); frame++) { // Vertices frames + if (!recTree->GetEvent(frame)) { + continue; + } + int contLabIdx{0}; // contributor labels are stored as flat vector + for (size_t iRecord{0}; iRecord < recVerROFArr->size(); ++iRecord) { + auto& rec = recVerROFArr->at(iRecord); + auto verStartIdx = rec.getFirstEntry(), verSize = rec.getNEntries(); + for (int iVertex{rec.getFirstEntry()}; iVertex < verStartIdx + verSize; ++iVertex) { + auto& info = vertexInfo.emplace_back(); + info.vertex = recVerArr->at(iVertex); + info.mainLabel = recVerLabelsArr->at(contLabIdx); + info.purity = recVerPurityArr->at(contLabIdx); + info.event = info.mainLabel.getEventID(); + ++contLabIdx; + if (info.mainLabel.isSet()) { + const auto& ir = irs[info.event]; + // LOGP(info, "iROF={} {} to {}", iRecord, info.mainLabel.asString(), ir.asString()); + if (!ir.isDummy()) { + info.bcInROF = (ir.toLong() - roFrameBiasInBC) % roFrameLengthInBC; + info.rofId = (ir.toLong() - roFrameBiasInBC) / roFrameLengthInBC; + } + } + } + } + } + std::cout << "done." << std::endl; + + auto hMCVtxZ = new TH1F("hMCVtxZ", "MC Vertex;Z", 50, -16, 16); + auto hReVtxZ = new TH1F("hRecoVtxZ", "Reco Vertex;Z", 50, -16, 16); + + auto hBCVtxDen = new TH1F("hBCVtxDen;bcInROF;eff.", "BC Den Vertices", roFbins, -0.5, roFbins - 0.5); + auto hBCVtxNum = new TH1F("hBCVtxNum;bcInROF;eff.", "BC Num Vertices", roFbins, -0.5, roFbins - 0.5); + + auto hBCVtxZDen = new TH2F("hBCVtxDen;bcInROF;z;eff.", "BC Den Vertices vs. z position", roFbins, -0.5, roFbins - 0.5, 40, -20, 20); + auto hBCVtxZNum = new TH2F("hBCVtxNum;bcInROF;z;eff.", "BC Num Vertices vs. z position", roFbins, -0.5, roFbins - 0.5, 40, -20, 20); + + auto pBCPurity = new TProfile("pBCProfile", ";bcInROF;", roFbins, -0.5, roFbins - 0.5); + auto pBCPurityDup = new TProfile("pBCProfileDup", ";bcInROF;", roFbins, -0.5, roFbins - 0.5); + pBCPurityDup->SetLineColor(kRed); + + auto hVtxMCx = new TH2F("hVtxMCx", ";MC_{x};Vtx_{x}", 100, -0.3, 0.3, 100, -0.3, 0.3); + auto hVtxMCy = new TH2F("hVtxMCy", ";MC_{y};Vtx_{y}", 100, -0.3, 0.3, 100, -0.3, 0.3); + auto hVtxMCz = new TH2F("hVtxMCz", ";MC_{z};Vtx_{z}", 100, -20, 20, 100, -20, 20); + + for (int n = 0; n < nev; n++) { // loop over MC events + mcTree->GetEvent(n); + hMCVtxZ->Fill(mcEvent->GetZ()); + const auto& ir = irs[mcEvent->GetEventID() - 1]; // event id start from 1 + if (!ir.isDummy()) { + int bcInROF = (ir.toLong() - roFrameBiasInBC) % roFrameLengthInBC; + hBCVtxDen->Fill(bcInROF); + hBCVtxZDen->Fill(bcInROF, mcEvent->GetZ()); + } + } + std::unordered_map seenMCEvent; + for (const auto& vtx : vertexInfo) { + ++seenMCEvent[vtx.mainLabel]; + } + // for (const auto& [k, f] : seenMCEvent) { + // LOGP(info, "{}:{} -> {} ({:.1f}%)", k.getSourceID(), k.getEventID(), f, 100.f * ((float)f / (float)vertexInfo.size())); + // } + LOGP(info, "received {} unique vertices", seenMCEvent.size()); + for (const auto& vtx : vertexInfo) { + if (!vtx.mainLabel.isValid() || vtx.bcInROF < 0 || vtx.event < 0) { + continue; + } + mcTree->GetEvent(vtx.event); + hVtxMCx->Fill(mcEvent->GetX(), vtx.vertex.getX()); + hVtxMCy->Fill(mcEvent->GetY(), vtx.vertex.getY()); + hVtxMCz->Fill(mcEvent->GetZ(), vtx.vertex.getZ()); + if (seenMCEvent[vtx.mainLabel] > 1) { + pBCPurityDup->Fill(vtx.bcInROF, vtx.purity); + } else { + hReVtxZ->Fill(vtx.vertex.getZ()); + hBCVtxNum->Fill(vtx.bcInROF); + hBCVtxZNum->Fill(vtx.bcInROF, vtx.vertex.getZ()); + pBCPurity->Fill(vtx.bcInROF, vtx.purity); + } + } + + auto hBCVtxNumClone = (TH1F*)hBCVtxNum->Clone(); + hBCVtxNumClone->SetTitle("unique Vertex;bcInROF;efficiency"); + hBCVtxNum->Divide(hBCVtxNum, hBCVtxDen, 1., 1., "b"); + + auto hBCVtxZNumClone = (TH2F*)hBCVtxZNum->Clone(); + hBCVtxZNumClone->SetTitle("unique Vertex;bcInROF;vtx.z;efficiency"); + hBCVtxZNumClone->Divide(hBCVtxZNum, hBCVtxZDen, 1., 1., "b"); + + hReVtxZ->Sumw2(); + hReVtxZ->SetLineColor(kRed); + + auto c = new TCanvas; + c->Divide(3, 2); + + c->cd(1); + auto hRatioVtxZ = new TRatioPlot(hReVtxZ, hMCVtxZ); + hRatioVtxZ->Draw(); + hRatioVtxZ->GetUpperPad()->cd(); + TLegend* legend = new TLegend(0.3, 0.7, 0.7, 0.85); + legend->SetHeader(Form("MC=%.0f Reco=%.0f", hMCVtxZ->GetEntries(), hReVtxZ->GetEntries())); + legend->AddEntry(hReVtxZ, "Reco", "l"); + legend->AddEntry(hMCVtxZ, "MC", "le"); + legend->Draw(); + gPad->Update(); + double max1 = hReVtxZ->GetMaximum(); + double max2 = hMCVtxZ->GetMaximum(); + double maxY = std::max(max1, max2); + hReVtxZ->GetYaxis()->SetRangeUser(0, maxY * 1.1); + + c->cd(2); + gPad->DrawFrame(-0.5, 1e-3, roFbins - 0.5, 1.1, "Vertex ;bcInROF;eff."); + hBCVtxNum->Draw("histe;same"); + + c->cd(3); + gPad->DrawFrame(-0.5, 1e-3, roFbins - 0.5, 1.1, "Purity;bcInROF;"); + pBCPurity->Draw(); + pBCPurityDup->Draw("same"); + c->Draw(); + + c->cd(4); + hBCVtxDen->Draw(); + c->cd(5); + hBCVtxNumClone->Draw(); + c->cd(6); + hBCVtxZNumClone->Draw(); + c->Draw(); + + c = new TCanvas; + c->Divide(3, 1); + c->cd(1); + hVtxMCx->Draw("colz"); + c->cd(2); + hVtxMCy->Draw("colz"); + c->cd(3); + hVtxMCz->Draw("colz"); + c->Draw(); + } + ////////////////////// + // Fake clusters + if (write) { + const int nby{4}, nbz{7}; + double ybins[nby + 1], zbins[nbz + 1]; + for (int i{0}; i < nby + 1; ++i) { + ybins[i] = (4 + i) - 0.5; + } + for (int i{0}; i < nbz + 1; ++i) { + zbins[i] = (0 + i) - 0.5; + } + auto hFakVal = new TH3D("fakClsVal", "Fake cluster attachment;#it{p}_{T} (GeV/#it{c});NCls;Fake;(fake-cluster rate)", nb, xbins, nby, ybins, nbz, zbins); + auto hFakMig = new TH3D("fakClsMig", "Fake cluster attachment;#it{p}_{T} (GeV/#it{c});NCls;Fake;(fake-cluster rate)", nb, xbins, nby, ybins, nbz, zbins); + + for (auto& event : info) { + for (auto& part : event) { + if (!part.isReconstructable()) { + continue; + } + + const auto& trk = part.track; + for (int iL{0}; iL < 7; ++iL) { + if (!trk.hasHitOnLayer(iL) || !trk.isFakeOnLayer(iL) || (part.clusters & (0x1 << iL)) == 0) { + continue; + } + // TODO: figure out how to find hit migration + // if (trk.hasHitInNextROF()) { + // hFakMig->Fill(trk.getPt(), trk.getNClusters(), iL); + // } else { + // hFakVal->Fill(trk.getPt(), trk.getNClusters(), iL); + // } + } + } + } + + hFakMig->Write(); + hFakVal->Write(); + } + if (fOut) { + fOut->Close(); + } + } else { + auto fWO = TFile::Open("checkDROF_wo.root"); + auto f = TFile::Open("checkDROF_w.root"); + plotHistos(fWO, f, ""); + plotHistos(fWO, f, "Val"); + plotHistos(fWO, f, "Mig"); + } +} + +void plotHistos(TFile* fWO, TFile* f, const char* append) +{ + TLegend* leg; + TH1* h; + const int woStyle = 1001; + const int wStyle = 3003; + const int ww{3840}, hh{2160}; + + const char* titlename = ""; + if (strcmp(append, "Val") == 0) { + titlename = ", Validation region"; + } else if (strcmp(append, "Mig") == 0) { + titlename = ", Migration region"; + } + + auto hWODen2 = fWO->Get(Form("den%s", append)); + hWODen2->SetName(Form("%s_wo", hWODen2->GetName())); + auto hWONum2 = fWO->Get(Form("num%s", append)); + hWONum2->SetName(Form("%s_wo", hWONum2->GetName())); + auto hWOFak2 = fWO->Get(Form("fak%s", append)); + hWOFak2->SetName(Form("%s_wo", hWOFak2->GetName())); + auto hWOSum2 = fWO->Get(Form("sum%s", append)); + hWOSum2->SetName(Form("%s_wo", hWOSum2->GetName())); + auto hWOMultiFak2 = fWO->Get(Form("multiFak%s", append)); + hWOMultiFak2->SetName(Form("%s_wo", hWOMultiFak2->GetName())); + + auto hWODenMC2 = fWO->Get(Form("denMC%s", append)); + hWODenMC2->SetName(Form("%s_wo", hWODenMC2->GetName())); + auto hWONumMC2 = fWO->Get(Form("numMC%s", append)); + hWONumMC2->SetName(Form("%s_wo", hWONumMC2->GetName())); + auto hWOFakMC2 = fWO->Get(Form("fakMC%s", append)); + hWOFakMC2->SetName(Form("%s_wo", hWOFakMC2->GetName())); + auto hWOSumMC2 = fWO->Get(Form("sumMC%s", append)); + hWOSumMC2->SetName(Form("%s_wo", hWOSumMC2->GetName())); + auto hWOMultiFakMC2 = fWO->Get(Form("multiFakMC%s", append)); + hWOMultiFakMC2->SetName(Form("%s_wo", hWOMultiFakMC2->GetName())); + + auto hWOBCTracksDen2 = fWO->Get(Form("hBCTracksDen%s", append)); + hWOBCTracksDen2->SetName(Form("%s_wo", hWOBCTracksDen2->GetName())); + auto hWOBCTracksNum2 = fWO->Get(Form("hBCTracksNum%s", append)); + hWOBCTracksNum2->SetName(Form("%s_wo", hWOBCTracksNum2->GetName())); + auto hWOBCTracksFake2 = fWO->Get(Form("hBCTracksFake%s", append)); + hWOBCTracksFake2->SetName(Form("%s_wo", hWOBCTracksFake2->GetName())); + auto hWOBCTracksSum2 = fWO->Get(Form("hBCTracksSum%s", append)); + hWOBCTracksSum2->SetName(Form("%s_wo", hWOBCTracksSum2->GetName())); + + auto setColor = [](TH1* h, EColor c) { + h->SetLineColor(c); + h->SetMarkerColor(c); + }; + auto hDen2 = f->Get(Form("den%s", append)); + setColor(hDen2, kBlack); + auto hNum2 = f->Get(Form("num%s", append)); + setColor(hNum2, kCyan); + auto hFak2 = f->Get(Form("fak%s", append)); + setColor(hFak2, kOrange); + auto hSum2 = f->Get(Form("sum%s", append)); + setColor(hSum2, kGray); + auto hMultiFak2 = f->Get(Form("multiFak%s", append)); + setColor(hMultiFak2, kMagenta); + + auto hDenMC2 = f->Get(Form("denMC%s", append)); + setColor(hDenMC2, kBlack); + auto hNumMC2 = f->Get(Form("numMC%s", append)); + setColor(hNumMC2, kCyan); + auto hFakMC2 = f->Get(Form("fakMC%s", append)); + setColor(hFakMC2, kOrange); + auto hSumMC2 = f->Get(Form("sumMC%s", append)); + setColor(hSumMC2, kGray); + auto hMultiFakMC2 = f->Get(Form("multiFakMC%s", append)); + setColor(hMultiFakMC2, kMagenta); + + auto hBCTracksDen2 = f->Get(Form("hBCTracksDen%s", append)); + setColor(hBCTracksDen2, kBlack); + auto hBCTracksNum2 = f->Get(Form("hBCTracksNum%s", append)); + setColor(hBCTracksNum2, kCyan); + auto hBCTracksFake2 = f->Get(Form("hBCTracksFake%s", append)); + setColor(hBCTracksFake2, kOrange); + auto hBCTracksSum2 = f->Get(Form("hBCTracksSum%s", append)); + setColor(hBCTracksSum2, kGray); + + int k = 0; + TCanvas *cEff = nullptr, *cBC = nullptr, *cCont = nullptr, *cRatio = nullptr; + { + auto plotTrkEff = [&](int i, int j) { + auto hWONum = hWONumMC2->ProjectionX(Form("%s_%d_%d_eff_px", hWONumMC2->GetName(), i, j), i, j); + auto hWODen = hWODenMC2->ProjectionX(Form("%s_%d_%d_eff_px", hWODenMC2->GetName(), i, j), 0, 5); + auto hWOFak = hWOFakMC2->ProjectionX(Form("%s_%d_%d_eff_px", hWOFakMC2->GetName(), i, j), i, j); + auto hWOMultiFak = hWOMultiFakMC2->ProjectionX(Form("%s_%d_%d_eff_px", hWOMultiFakMC2->GetName(), i, j), i, j); + auto hWOSum = (TH1D*)hWONum->Clone(Form("%s_sum_eff__%d", hWONum->GetName(), j)); + hWOSum->Add(hWOFak); + + hWOSum->Divide(hWOSum, hWODen, 1., 1., "B"); + hWOSum->SetFillColorAlpha(hWOSum2->GetLineColor(), 0.5); + hWOSum->SetFillStyle(woStyle); + hWOSum->Draw("histe;same"); + + hWONum->Divide(hWONum, hWODen, 1., 1., "B"); + hWONum->SetFillColorAlpha(hWONum2->GetLineColor(), 0.5); + hWONum->SetFillStyle(woStyle); + hWONum->Draw("histe;same"); + + hWOFak->Divide(hWOFak, hWODen, 1., 1., "B"); + hWOFak->SetFillColorAlpha(hWOFak2->GetLineColor(), 0.5); + hWOFak->SetFillStyle(woStyle); + hWOFak->Draw("histe;same"); + + hWOMultiFak->Divide(hWOMultiFak, hWODen, 1., 1., "B"); + hWOMultiFak->SetLineColor(hWOMultiFak2->GetLineColor()); + hWOMultiFak->SetFillColorAlpha(hWOMultiFak2->GetLineColor(), 0.5); + hWOMultiFak->SetFillStyle(woStyle); + // hWOMultiFak->Draw("histe;same"); + + auto hNum = hNum2->ProjectionX(Form("%s_%d_%d_eff_px", hNumMC2->GetName(), i, j), i, j); + auto hDen = hDen2->ProjectionX(Form("%s_%d_%d_eff_px", hDenMC2->GetName(), i, j), 0, 5); + auto hFak = hFak2->ProjectionX(Form("%s_%d_%d_eff_px", hFakMC2->GetName(), i, j), i, j); + auto hMultiFak = hMultiFak2->ProjectionX(Form("%s_%d_%d_px", hMultiFakMC2->GetName(), i, j), i, j); + auto hSum = (TH1D*)hNum->Clone(Form("%s_sum_eff_%d", hNum->GetName(), j)); + hSum->Add(hFak); + + hSum->Divide(hSum, hDen, 1., 1., "B"); + hSum->SetFillColor(hSum2->GetLineColor()); + hSum->SetLineColor(hSum2->GetLineColor()); + hSum->SetFillStyle(wStyle); + hSum->Draw("histe;same"); + + hNum->Divide(hNum, hDen, 1., 1., "B"); + hNum->SetFillColor(hNum2->GetLineColor()); + hNum->SetLineColor(hNum2->GetLineColor()); + hNum->SetFillStyle(wStyle); + hNum->Draw("histe;same"); + + hFak->Divide(hFak, hDen, 1., 1., "B"); + hFak->SetFillColor(hFak2->GetLineColor()); + hFak->SetLineColor(hFak2->GetLineColor()); + hFak->SetFillStyle(wStyle); + hFak->Draw("histe;same"); + + hMultiFak->Divide(hMultiFak, hDen, 1., 1., "B"); + hMultiFak->SetLineColor(hMultiFak2->GetLineColor()); + hMultiFak->SetFillColor(hMultiFak2->GetLineColor()); + hMultiFak->SetFillStyle(wStyle); + // hMultiFak->Draw("histe;same"); + + if (i == 1 && i == j) { + leg = new TLegend(0.1, 0.1, 0.9, 0.9); + leg->AddEntry((TObject*)0, "deltaRof=0", ""); + leg->AddEntry(hWOSum, "sum"); + leg->AddEntry(hWONum, "good"); + leg->AddEntry(hWOFak, "fake"); + // leg->AddEntry(hWOMultiFak, "multifake"); + leg->AddEntry((TObject*)0, "deltaRof=1", ""); + leg->AddEntry(hSum, "sum"); + leg->AddEntry(hNum, "good"); + leg->AddEntry(hFak, "fake"); + // leg->AddEntry(hMultiFak, "multifake"); + } + }; + + cEff = new TCanvas(Form("pteff%s", append), "", ww, hh); + cEff->Divide(3, 2); + k = 0; + for (int i{1}; i <= 4; ++i) { + if (i == 3) { + ++k; + } + cEff->cd(i + k); + h = gPad->DrawFrame( + 0.02, 0, 10, 1.02, + Form("Tracking Efficiency #times Fraction (7 MC hits, %d-point " + "tracks%s);#it{p}_{T,MC} GeV/#it{c};eff. (fake-rate)", + 3 + i, titlename)); + h->GetXaxis()->SetTitleOffset(1.4); + + plotTrkEff(i, i); + + gPad->SetLogx(); + gPad->SetGrid(); + gPad->RedrawAxis("g"); + } + cEff->cd(3); + h = gPad->DrawFrame( + 0.02, 0, 10, 1.02, + Form("Tracking Efficiency (7 MC hits, all point " + "tracks%s);#it{p}_{T,MC} GeV/#it{c};eff. (fake-rate)", + titlename)); + h->GetXaxis()->SetTitleOffset(1.4); + + plotTrkEff(1, 4); + + gPad->SetLogx(); + gPad->SetGrid(); + gPad->RedrawAxis("g"); + + cEff->cd(6); + leg->Draw(); + } + + { + auto plotRatios = [&](int i, int j, TPad* upper, TPad* lower) { + auto hWONum = hWONumMC2->ProjectionX(Form("%s_%d_%d_ratio_px", hWONumMC2->GetName(), i, j), i, j); + auto hWOFak = hWOFakMC2->ProjectionX(Form("%s_%d_%d_ratio_px", hWOFakMC2->GetName(), i, j), i, j); + + hWONum->SetFillColorAlpha(hWONum2->GetLineColor(), 0.5); + hWONum->SetLineColor(hWONum2->GetLineColor()); + // hWONum->SetFillStyle(woStyle); + + hWOFak->SetFillColorAlpha(hWOFak2->GetLineColor(), 0.5); + hWOFak->SetLineColor(hWOFak2->GetLineColor()); + // hWOFak->SetFillStyle(woStyle); + + auto hNum = hNum2->ProjectionX(Form("%s_%d_%d_ratio_px", hNumMC2->GetName(), i, j), i, j); + auto hFak = hFak2->ProjectionX(Form("%s_%d_%d_ratio_px", hFakMC2->GetName(), i, j), i, j); + + hNum->SetFillColor(hNum2->GetLineColor()); + hNum->SetLineColor(hNum2->GetLineColor()); + // hNum->SetFillStyle(wStyle); + + hFak->SetFillColor(hFak2->GetLineColor()); + hFak->SetLineColor(hFak2->GetLineColor()); + // hFak->SetFillStyle(wStyle); + // + upper->cd(); + upper->SetLogx(); + upper->SetGrid(); + hWONum->Draw("hist"); + hWOFak->Draw("hist same"); + hNum->Draw("hist same"); + hFak->Draw("hist same"); + double ymax = 1.1 * std::max({hNum->GetMaximum(), hFak->GetMaximum(), hWONum->GetMaximum(), hWOFak->GetMaximum()}); + hWONum->GetYaxis()->SetRangeUser(0, ymax); + gPad->RedrawAxis("g"); + + auto rNum = (TH1*)hNum->Clone(Form("rNum_%s_%d_%d", hNum->GetName(), i, j)); + auto rFak = (TH1*)hFak->Clone(Form("rFak_%s_%d_%d", hFak->GetName(), i, j)); + rNum->GetYaxis()->SetTitle("(deltaRof=1) / (deltaRof=0)"); + rNum->Divide(hWONum); + rFak->Divide(hWOFak); + + // rNum->SetMarkerStyle(20); + // rFak->SetMarkerStyle(21); + rNum->SetLineWidth(2); + rFak->SetLineWidth(2); + rNum->SetFillStyle(0); + rFak->SetFillStyle(0); + setColor(rNum, kBlue); + setColor(rFak, kRed); + double ymin = std::min(rNum->GetMinimum(0.0), rFak->GetMinimum(0.0)); + ymax = std::max(rNum->GetMaximum(), rFak->GetMaximum()); + double ypad = 0.1 * (ymax - ymin); + ymin -= ypad; + ymax += ypad; + + lower->cd(); + lower->SetLogx(); + lower->SetGrid(); + rNum->GetYaxis()->SetRangeUser(ymin, ymax); + rNum->Draw("hist"); + rFak->Draw("hist;same"); + gPad->RedrawAxis("g"); + + if (i == 1 && i == j) { + leg = new TLegend(0.1, 0.1, 0.9, 0.9); + leg->AddEntry((TObject*)0, "deltaRof=0", ""); + leg->AddEntry(hWONum, "good"); + leg->AddEntry(hWOFak, "fake"); + leg->AddEntry((TObject*)0, "deltaRof=1", ""); + leg->AddEntry(hNum, "good"); + leg->AddEntry(hFak, "fake"); + leg->AddEntry((TObject*)0, "Ratios", ""); + leg->AddEntry(rNum, "good", "l"); + leg->AddEntry(rFak, "fake", "l"); + } + }; + + cRatio = new TCanvas(Form("ptratio%s", append), "", ww, hh); + cRatio->Divide(3, 2); + k = 0; + for (int i{1}; i <= 4; ++i) { + if (i == 3) { + ++k; + } + cRatio->cd(i + k); + TPad* up = new TPad(Form("up%d", k), "", 0, 0.5, 1, 1); + TPad* dn = new TPad(Form("dn%d", k), "", 0, 0, 1, 0.5); + up->SetBottomMargin(0); + dn->SetTopMargin(0); + up->Draw(); + dn->Draw(); + + plotRatios(i, i, up, dn); + } + cRatio->cd(3); + TPad* up = new TPad(Form("up_e_%d", k), "", 0, 0.5, 1, 1); + TPad* dn = new TPad(Form("dn_e_%d", k), "", 0, 0, 1, 0.5); + up->SetBottomMargin(0); + dn->SetTopMargin(0); + up->Draw(); + dn->Draw(); + plotRatios(1, 4, up, dn); + + cRatio->cd(6); + leg->Draw(); + } + + { + auto plotTrkCont = [&](int i, int j) { + auto hWONum = hWONum2->ProjectionX(Form("%s_%d_%d_cont_px", hWONum2->GetName(), i, j), i, j); + auto hWODen = hWODen2->ProjectionX(Form("%s_%d_%d_cont_px", hWODen2->GetName(), i, j), 0, 5); + auto hWOFak = hWOFak2->ProjectionX(Form("%s_%d_%d_cont_px", hWOFak2->GetName(), i, j), i, j); + auto hWOMultiFak = hWOMultiFak2->ProjectionX(Form("%s_%d_%d_cont_px", hWOMultiFak2->GetName(), i, j), i, j); + auto hWOSum = (TH1D*)hWONum->Clone(Form("%s_sum_cont_%d", hWONum->GetName(), j)); + hWOSum->Add(hWOFak); + + hWOSum->Divide(hWOSum, hWODen, 1., 1., "B"); + hWOSum->SetFillColorAlpha(hWOSum2->GetLineColor(), 0.5); + hWOSum->SetFillStyle(woStyle); + // hWOSum->Draw("histe;same"); + + hWONum->Divide(hWONum, hWODen, 1., 1., "B"); + hWONum->SetFillColorAlpha(hWONum2->GetLineColor(), 0.5); + hWONum->SetFillStyle(woStyle); + hWONum->Draw("histe;same"); + + hWOFak->Divide(hWOFak, hWODen, 1., 1., "B"); + hWOFak->SetFillColorAlpha(hWOFak2->GetLineColor(), 0.5); + hWOFak->SetFillStyle(woStyle); + hWOFak->Draw("histe;same"); + + hWOMultiFak->Divide(hWOMultiFak, hWODen, 1., 1., "B"); + hWOMultiFak->SetLineColor(hWOMultiFak2->GetLineColor()); + hWOMultiFak->SetFillColorAlpha(hWOMultiFak2->GetLineColor(), 0.5); + hWOMultiFak->SetFillStyle(woStyle); + // hWOMultiFak->Draw("histe;same"); + + auto hNum = hNum2->ProjectionX(Form("%s_%d_%d_cont_px", hNum2->GetName(), i, j), i, j); + auto hDen = hDen2->ProjectionX(Form("%s_%d_%d_cont_px", hDen2->GetName(), i, j), 0, 5); + auto hFak = hFak2->ProjectionX(Form("%s_%d_%d_cont_px", hFak2->GetName(), i, j), i, j); + auto hMultiFak = hMultiFak2->ProjectionX(Form("%s_%d_%d_px", hMultiFak2->GetName(), i, j), i, j); + auto hSum = (TH1D*)hNum->Clone(Form("%s_sum_cont_%d", hNum->GetName(), j)); + hSum->Add(hFak); + + hSum->Divide(hSum, hDen, 1., 1., "B"); + hSum->SetFillColor(hSum2->GetLineColor()); + hSum->SetFillStyle(wStyle); + // hSum->Draw("histe;same"); + + hNum->Divide(hNum, hDen, 1., 1., "B"); + hNum->SetFillColor(hNum2->GetLineColor()); + hNum->SetFillStyle(wStyle); + hNum->Draw("histe;same"); + + hFak->Divide(hFak, hDen, 1., 1., "B"); + hFak->SetFillColor(hFak2->GetLineColor()); + hFak->SetFillStyle(wStyle); + hFak->Draw("histe;same"); + + hMultiFak->Divide(hMultiFak, hDen, 1., 1., "B"); + hMultiFak->SetLineColor(hMultiFak2->GetLineColor()); + hMultiFak->SetFillColor(hMultiFak2->GetLineColor()); + hMultiFak->SetFillStyle(wStyle); + // hMultiFak->Draw("histe;same"); + + if (i == 1 && i == j) { + leg = new TLegend(0.1, 0.1, 0.9, 0.9); + leg->AddEntry((TObject*)0, "deltaRof=0", ""); + leg->AddEntry(hWONum, "good"); + leg->AddEntry(hWOFak, "fake"); + // leg->AddEntry(hWOMultiFak, "multifake"); + leg->AddEntry((TObject*)0, "deltaRof=1", ""); + leg->AddEntry(hNum, "DROF:good"); + leg->AddEntry(hFak, "DROF:fake"); + // leg->AddEntry(hMultiFak, "DROF:multifake"); + } + }; + + cCont = new TCanvas(Form("ptcont%s", append), "", ww, hh); + cCont->Divide(3, 2); + k = 0; + for (int i{1}; i <= 4; ++i) { + if (i == 3) { + ++k; + } + cCont->cd(i + k); + h = gPad->DrawFrame( + 0.02, 0, 10, 1.02, + Form("Tracking Contribution #times Fraction (7 MC hits, %d-point " + "tracks%s);#it{p}_{T,Reco} GeV/#it{c};contribtution", + 3 + i, titlename)); + h->GetXaxis()->SetTitleOffset(1.4); + + plotTrkCont(i, i); + + gPad->SetLogx(); + gPad->SetGrid(); + gPad->RedrawAxis("g"); + } + cCont->cd(3); + h = gPad->DrawFrame(0.02, 0, 10, 1.02, + Form("Tracking Contribution (7 MC hits, all point " + "tracks%s);#it{p}_{T,Reco} GeV/#it{c};contribution", + titlename)); + h->GetXaxis()->SetTitleOffset(1.4); + + plotTrkCont(1, 4); + + gPad->SetLogx(); + gPad->SetGrid(); + gPad->RedrawAxis("g"); + + cCont->cd(6); + leg->Draw(); + } + + { + auto plotBCEff = [&](int i, int j) { + auto hWOBCTracksNum = hWOBCTracksNum2->ProjectionX(Form("%s_%d_%d_bc_px", hWOBCTracksNum2->GetName(), i, j), i, j); + auto hWOBCTracksDen = hWOBCTracksDen2->ProjectionX(Form("%s_%d_%d_bc_px", hWOBCTracksDen2->GetName(), i, j), 0, 5); + auto hWOBCTracksFake = hWOBCTracksFake2->ProjectionX(Form("%s_%d_%d_bc_px", hWOBCTracksFake2->GetName(), i, j), i, j); + auto hWOBCTracksSum = (TH1F*)hWOBCTracksNum->Clone(Form("%s_%d_sum", hWOBCTracksNum->GetName(), j)); + hWOBCTracksSum->Add(hWOBCTracksFake); + + hWOBCTracksSum->Divide(hWOBCTracksSum, hWOBCTracksDen, 1., 1., "B"); + hWOBCTracksSum->SetLineColor(hWOSum2->GetLineColor()); + hWOBCTracksSum->SetFillColorAlpha(hWOSum2->GetLineColor(), 0.5); + hWOBCTracksSum->SetFillStyle(woStyle); + hWOBCTracksSum->Draw("histe;same"); + + hWOBCTracksNum->Divide(hWOBCTracksNum, hWOBCTracksDen, 1., 1., "B"); + hWOBCTracksNum->SetLineColor(hWONum2->GetLineColor()); + hWOBCTracksNum->SetFillColorAlpha(hWONum2->GetLineColor(), 0.5); + hWOBCTracksNum->SetFillStyle(woStyle); + hWOBCTracksNum->Draw("histe;same"); + + hWOBCTracksFake->Divide(hWOBCTracksFake, hWOBCTracksDen, 1., 1., "B"); + hWOBCTracksFake->SetLineColor(hWOFak2->GetLineColor()); + hWOBCTracksFake->SetFillColorAlpha(hWOFak2->GetLineColor(), 0.5); + hWOBCTracksFake->SetFillStyle(woStyle); + hWOBCTracksFake->Draw("histe;same"); + + auto hBCTracksNum = hBCTracksNum2->ProjectionX(Form("%s_%d_%d_bc_px", hBCTracksNum2->GetName(), i, j), i, j); + auto hBCTracksDen = hBCTracksDen2->ProjectionX(Form("%s_%d_%d_bc_px", hBCTracksDen2->GetName(), i, j), 0, 5); + auto hBCTracksFake = hBCTracksFake2->ProjectionX(Form("%s_%d_%d_bc_px", hBCTracksFake2->GetName(), i, j), i, j); + auto hBCTracksSum = (TH1F*)hBCTracksNum->Clone(Form("%s_%d_sum", hBCTracksNum->GetName(), j)); + hBCTracksSum->Add(hBCTracksFake); + + hBCTracksSum->Divide(hBCTracksSum, hBCTracksDen, 1., 1., "B"); + hBCTracksSum->SetLineColor(hSum2->GetLineColor()); + hBCTracksSum->SetFillColor(hSum2->GetLineColor()); + hBCTracksSum->SetFillStyle(wStyle); + hBCTracksSum->Draw("histe;same"); + + hBCTracksNum->Divide(hBCTracksNum, hBCTracksDen, 1., 1., "B"); + hBCTracksNum->SetLineColor(hNum2->GetLineColor()); + hBCTracksNum->SetFillColor(hNum2->GetLineColor()); + hBCTracksNum->SetFillStyle(wStyle); + hBCTracksNum->Draw("histe;same"); + + hBCTracksFake->Divide(hBCTracksFake, hBCTracksDen, 1., 1., "B"); + hBCTracksFake->SetLineColor(hFak2->GetLineColor()); + hBCTracksFake->SetFillColor(hFak2->GetLineColor()); + hBCTracksFake->SetFillStyle(wStyle); + hBCTracksFake->Draw("histe;same"); + + if (i == 1 && i == j) { + leg = new TLegend(0.1, 0.1, 0.9, 0.9); + leg->AddEntry((TObject*)0, "deltaRof=0", ""); + leg->AddEntry(hWOBCTracksNum, "good"); + leg->AddEntry(hWOBCTracksFake, "fake"); + leg->AddEntry(hWOBCTracksSum, "sum"); + leg->AddEntry((TObject*)0, "deltaRof=1", ""); + leg->AddEntry(hBCTracksNum, "good"); + leg->AddEntry(hBCTracksFake, "fake"); + leg->AddEntry(hBCTracksSum, "sum"); + } + }; + + cBC = new TCanvas(Form("bceff%s", append), "", ww, hh); + cBC->Divide(3, 2); + k = 0; + for (int i{1}; i <= 4; ++i) { + if (i == 3) { + ++k; + } + cBC->cd(i + k); + gPad->DrawFrame(-0.5, 0, 200 - 0.5, 1.02, + Form("Tracking Efficiency #times Fraction (#it{p}_{T} " + "integrated, %d-point " + "tracks%s);BC in " + "ROF;eff. (fake-rate)", + 3 + i, titlename)); + plotBCEff(i, i); + gPad->SetGrid(); + gPad->RedrawAxis("g"); + } + cBC->cd(3); + gPad->DrawFrame(-0.5, 0, 200 - 0.5, 1.02, + Form("Tracking Efficiency (#it{p}_{T} " + "integrated, all point " + "tracks%s);BC in " + "ROF;eff. (fake-rate)", + titlename)); + plotBCEff(1, 4); + gPad->SetGrid(); + gPad->RedrawAxis("g"); + + cBC->cd(6); + leg->Draw(); + } + + TString outname = TString::Format("trkeff%s.pdf", append); + cEff->cd(); + cEff->Update(); + cEff->Print(TString::Format("%s(", outname.Data()), "Title:Tracking Efficiency"); + cRatio->cd(); + cRatio->Update(); + cRatio->Print(outname.Data(), "Title:Ratios"); + cCont->cd(); + cCont->Update(); + cCont->Print(outname.Data(), "Title:Contribution"); + cBC->cd(); + cBC->Update(); + cBC->Print(TString::Format("%s)", outname.Data()), "Title:BC"); +} diff --git a/Detectors/ITSMFT/ITS/macros/test/CheckSeeding.C b/Detectors/ITSMFT/ITS/macros/test/CheckSeeding.C new file mode 100644 index 0000000000000..915f2dda75032 --- /dev/null +++ b/Detectors/ITSMFT/ITS/macros/test/CheckSeeding.C @@ -0,0 +1,706 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DataFormatsITS/Vertex.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTrack.h" +#include "SimulationDataFormat/O2DatabasePDG.h" +#include "Steer/MCKinematicsReader.h" +#endif + +constexpr const char* tracFile = "o2trac_its.root"; +constexpr const char* collContextFile = "collisioncontext.root"; + +namespace +{ +namespace fs = std::filesystem; + +constexpr float MinPt = 0.05f; +constexpr float MaxEta = 1.1f; +constexpr int NMultiplicityBins = 11; +constexpr std::array MultiplicityLabels{{"2", "3", "4-5", "6-8", "9-13", "14-21", "22-33", "34-52", "53-83", "84-128", "128+"}}; + +struct TruthInfo { + int multiplicity = 0; + float x = 0.f; + float y = 0.f; + float z = 0.f; +}; + +struct BestRecoInfo { + o2::its::Vertex vertex; + float purity = -1.f; +}; + +struct GaussianSummary { + bool valid = false; + double mean = 0.; + double sigma = 0.; +}; + +bool isTrueVertexLabel(const o2::MCCompLabel& label) +{ + return label.isValid() && !label.isFake() && label.getSourceID() == 0; +} + +bool isChargedPrimary(const o2::MCTrack& track) +{ + if (!track.isPrimary() || track.GetPt() < MinPt || std::abs(track.GetEta()) > MaxEta) { + return false; + } + auto* pdg = o2::O2DatabasePDG::Instance()->GetParticle(track.GetPdgCode()); + return pdg != nullptr && pdg->Charge() != 0.; +} + +bool isBetterReco(const o2::its::Vertex& candidate, float candidatePurity, const o2::its::Vertex& current, float currentPurity) +{ + if (candidatePurity != currentPurity) { + return candidatePurity > currentPurity; + } + if (candidate.getNContributors() != current.getNContributors()) { + return candidate.getNContributors() > current.getNContributors(); + } + return candidate.getChi2() < current.getChi2(); +} + +int getMultiplicityCategory(int multiplicity) +{ + if (multiplicity <= 2) { + return 1; + } + if (multiplicity <= 3) { + return 2; + } + if (multiplicity <= 5) { + return 3; + } + if (multiplicity <= 8) { + return 4; + } + if (multiplicity <= 13) { + return 5; + } + if (multiplicity <= 21) { + return 6; + } + if (multiplicity <= 33) { + return 7; + } + if (multiplicity <= 52) { + return 8; + } + if (multiplicity <= 83) { + return 9; + } + if (multiplicity <= 128) { + return 10; + } + return 11; +} + +void fillMultiplicityHistogram(TH1* hist, int multiplicity) +{ + hist->Fill(getMultiplicityCategory(multiplicity)); +} + +GaussianSummary fitGaussianCore(TH1* hist, const char* funcName) +{ + if (hist == nullptr || hist->GetEntries() < 20) { + return {}; + } + const auto rms = hist->GetRMS(); + if (!(rms > 0.)) { + return {}; + } + + TF1 fit(funcName, "gaus", hist->GetMean() - 2. * rms, hist->GetMean() + 2. * rms); + fit.SetParameters(hist->GetMaximum(), hist->GetMean(), rms); + hist->Fit(&fit, "Q0R"); + + const auto mean = fit.GetParameter(1); + const auto sigma = std::abs(fit.GetParameter(2)); + if (!(sigma > 0.)) { + return {}; + } + + fit.SetRange(mean - 2. * sigma, mean + 2. * sigma); + hist->Fit(&fit, "Q0R"); + return {true, fit.GetParameter(1), std::abs(fit.GetParameter(2))}; +} + +TH1D* makeNormalizedCopy(const TH1D* source, const char* name, const char* title) +{ + auto* copy = static_cast(source->Clone(name)); + copy->SetTitle(title); + const auto integral = copy->Integral("width"); + if (integral > 0.) { + copy->Scale(1. / integral); + } + return copy; +} + +void setMultiplicityBinLabels(TH1* hist) +{ + for (int i = 0; i < NMultiplicityBins; ++i) { + hist->GetXaxis()->SetBinLabel(i + 1, MultiplicityLabels[i]); + } +} + +void setHistogramStyle(TH1* hist, int color, int marker) +{ + hist->SetLineColor(color); + hist->SetMarkerColor(color); + hist->SetMarkerStyle(marker); + hist->SetLineWidth(2); +} + +void printGaussianByMultiplicity(const std::array& summaries, const char* title) +{ + std::printf("%s:\n", title); + for (int i = 0; i < NMultiplicityBins; ++i) { + if (summaries[i].valid) { + std::printf(" %-4s : mean=%.6g sigma=%.6g\n", MultiplicityLabels[i], summaries[i].mean, summaries[i].sigma); + } else { + std::printf(" %-4s : n/a\n", MultiplicityLabels[i]); + } + } +} + +fs::path resolveContextFile(const fs::path& dir) +{ + const std::array candidates{ + dir / collContextFile, + dir.parent_path() / collContextFile, + fs::current_path() / collContextFile}; + for (const auto& candidate : candidates) { + if (!candidate.empty() && fs::exists(candidate) && fs::is_regular_file(candidate)) { + return candidate; + } + } + return {}; +} + +void printBinnedFractions(const TH1* numerator, const TH1* denominator, const char* title) +{ + if (numerator == nullptr || denominator == nullptr) { + return; + } + std::printf("%s:\n", title); + for (int iBin = 1; iBin <= denominator->GetNbinsX(); ++iBin) { + const auto den = denominator->GetBinContent(iBin); + const auto num = numerator->GetBinContent(iBin); + const auto value = den > 0. ? num / den : 0.; + std::printf(" %-4s : %.4f (%g / %g)\n", denominator->GetXaxis()->GetBinLabel(iBin), value, num, den); + } +} + +std::vector findDirs(const std::string& roots) +{ + fs::path root = roots.empty() ? fs::current_path() : fs::path{roots}; + std::vector result; + const auto hasFiles = [](const fs::path& dir) { + const auto tracPath = dir / tracFile; + return fs::exists(tracPath) && fs::is_regular_file(tracPath); + }; + + if (fs::is_directory(root) && hasFiles(root)) { + result.push_back(root); + return result; + } + + for (const auto& entry : fs::recursive_directory_iterator(root)) { + if (entry.is_directory() && hasFiles(entry.path())) { + result.push_back(entry.path()); + } + } + std::sort(result.begin(), result.end()); + return result; +} + +} // namespace + +void CheckSeeding(const std::string& dir = "") +{ + using Vertex = o2::its::Vertex; + const auto cwd = fs::current_path(); + gStyle->SetOptStat(0); + TH1::AddDirectory(kFALSE); + + auto dirs = findDirs(dir); + std::printf("Will iterate over %zu input dirs\n", dirs.size()); + if (dirs.empty()) { + std::printf("No input directories containing %s were found.\n", tracFile); + return; + } + + auto* hTruthMultiplicityFindable = new TH1D("hTruthMultiplicityFindable", + "Findable truth vertices;truth multiplicity bin;vertices", + NMultiplicityBins, 0.5, NMultiplicityBins + 0.5); + auto* hTruthMultiplicityFound = new TH1D("hTruthMultiplicityFound", + "Found truth vertices;truth multiplicity bin;vertices", + NMultiplicityBins, 0.5, NMultiplicityBins + 0.5); + auto* hRecoMultiplicityTrue = new TH1D("hRecoMultiplicityTrue", + "True reconstructed vertices;reco multiplicity bin;vertices", + NMultiplicityBins, 0.5, NMultiplicityBins + 0.5); + auto* hRecoMultiplicityFake = new TH1D("hRecoMultiplicityFake", + "Fake reconstructed vertices;reco multiplicity bin;vertices", + NMultiplicityBins, 0.5, NMultiplicityBins + 0.5); + auto* hDx = new TH1D("hDx", "Matched vertex residuals;x_{reco}-x_{MC} (cm);vertices", 400, -0.02, 0.02); + auto* hDy = new TH1D("hDy", "Matched vertex residuals;y_{reco}-y_{MC} (cm);vertices", 400, -0.02, 0.02); + auto* hDz = new TH1D("hDz", "Matched vertex residuals;z_{reco}-z_{MC} (cm);vertices", 400, -0.02, 0.02); + auto* hPullX = new TH1D("hPullX", "Matched vertex pulls;x pull;vertices", 600, -30., 30.); + auto* hPullY = new TH1D("hPullY", "Matched vertex pulls;y pull;vertices", 600, -30., 30.); + auto* hPullZ = new TH1D("hPullZ", "Matched vertex pulls;z pull;vertices", 600, -30., 30.); + std::array hPullXByMult{}; + std::array hPullYByMult{}; + std::array hPullZByMult{}; + for (int i = 0; i < NMultiplicityBins; ++i) { + const auto nameX = std::string("hPullX_") + std::to_string(i + 1); + const auto nameY = std::string("hPullY_") + std::to_string(i + 1); + const auto nameZ = std::string("hPullZ_") + std::to_string(i + 1); + const auto titleX = std::string("x pull ") + MultiplicityLabels[i] + ";x pull;vertices"; + const auto titleY = std::string("y pull ") + MultiplicityLabels[i] + ";y pull;vertices"; + const auto titleZ = std::string("z pull ") + MultiplicityLabels[i] + ";z pull;vertices"; + hPullXByMult[i] = new TH1D(nameX.c_str(), titleX.c_str(), 600, -30., 30.); + hPullYByMult[i] = new TH1D(nameY.c_str(), titleY.c_str(), 600, -30., 30.); + hPullZByMult[i] = new TH1D(nameZ.c_str(), titleZ.c_str(), 600, -30., 30.); + } + + setMultiplicityBinLabels(hTruthMultiplicityFindable); + setMultiplicityBinLabels(hTruthMultiplicityFound); + setMultiplicityBinLabels(hRecoMultiplicityTrue); + setMultiplicityBinLabels(hRecoMultiplicityFake); + setHistogramStyle(hTruthMultiplicityFindable, kGray + 2, 20); + setHistogramStyle(hTruthMultiplicityFound, kAzure + 2, 20); + setHistogramStyle(hRecoMultiplicityTrue, kAzure + 2, 20); + setHistogramStyle(hRecoMultiplicityFake, kOrange + 7, 24); + setHistogramStyle(hDx, kAzure + 2, 20); + setHistogramStyle(hDy, kGreen + 2, 21); + setHistogramStyle(hDz, kRed + 1, 24); + setHistogramStyle(hPullX, kAzure + 2, 20); + setHistogramStyle(hPullY, kGreen + 2, 21); + setHistogramStyle(hPullZ, kRed + 1, 24); + + size_t findable = 0; + size_t totalFound = 0; + size_t trueFound = 0; + size_t fakeFound = 0; + size_t uniqueTrueReco = 0; + size_t uniqueFindableFound = 0; + size_t sigmaXCount = 0; + size_t sigmaYCount = 0; + size_t sigmaZCount = 0; + double sumSigmaX = 0.; + double sumSigmaY = 0.; + double sumSigmaZ = 0.; + + for (const auto& inputDir : dirs) { + fs::current_path(inputDir); + std::printf("Working on %s\n", inputDir.c_str()); + const auto contextPath = resolveContextFile(inputDir); + if (contextPath.empty()) { + std::printf("Skipping %s: could not locate %s\n", inputDir.c_str(), collContextFile); + continue; + } + + o2::steer::MCKinematicsReader mcReader(contextPath.string()); + if (!mcReader.isInitialized()) { + std::printf("Skipping %s: failed to initialize MCKinematicsReader from %s\n", inputDir.c_str(), contextPath.c_str()); + continue; + } + + std::unordered_map findableTruths; + std::unordered_set uniqueTrueLabelsReco; + std::unordered_set uniqueFindableTruthFound; + std::unordered_map bestRecoByTruth; + + const int iSrc = 0; + const auto nEvents = static_cast(mcReader.getNEvents(iSrc)); + for (int iEve = 0; iEve < nEvents; ++iEve) { + const auto& tracks = mcReader.getTracks(iSrc, iEve); + const auto contributors = static_cast(std::count_if(tracks.begin(), tracks.end(), isChargedPrimary)); + if (contributors >= 2) { + const auto& header = mcReader.getMCEventHeader(iSrc, iEve); + findableTruths.emplace(iEve, TruthInfo{contributors, (float)header.GetX(), (float)header.GetY(), (float)header.GetZ()}); + fillMultiplicityHistogram(hTruthMultiplicityFindable, contributors); + } + mcReader.releaseTracksForSourceAndEvent(iSrc, iEve); + } + + auto* tracFileHandle = TFile::Open((inputDir / tracFile).c_str()); + if (tracFileHandle == nullptr || tracFileHandle->IsZombie()) { + std::printf("Skipping %s: failed to open %s\n", inputDir.c_str(), tracFile); + delete tracFileHandle; + continue; + } + + auto* tracTree = tracFileHandle->Get("o2sim"); + if (tracTree == nullptr) { + std::printf("Skipping %s: missing o2sim tree in %s\n", inputDir.c_str(), tracFile); + tracFileHandle->Close(); + delete tracFileHandle; + continue; + } + + if (tracTree->GetBranch("Vertices") == nullptr || tracTree->GetBranch("ITSVertexMCTruth") == nullptr) { + std::printf("Skipping %s: missing vertex branches in %s\n", inputDir.c_str(), tracFile); + tracFileHandle->Close(); + delete tracFileHandle; + continue; + } + + std::vector* vertices = nullptr; + std::vector* labels = nullptr; + std::vector* purities = nullptr; + const bool hasPurityBranch = tracTree->GetBranch("ITSVertexMCPurity") != nullptr; + + tracTree->SetBranchAddress("Vertices", &vertices); + tracTree->SetBranchAddress("ITSVertexMCTruth", &labels); + if (hasPurityBranch) { + tracTree->SetBranchAddress("ITSVertexMCPurity", &purities); + } + + const auto nEntries = tracTree->GetEntriesFast(); + for (Long64_t iEntry = 0; iEntry < nEntries; ++iEntry) { + tracTree->GetEntry(iEntry); + if (vertices == nullptr || labels == nullptr) { + continue; + } + auto nVertices = std::min(vertices->size(), labels->size()); + if (hasPurityBranch && purities != nullptr) { + nVertices = std::min(nVertices, purities->size()); + } + + for (size_t iVtx = 0; iVtx < nVertices; ++iVtx) { + const auto& vertex = (*vertices)[iVtx]; + const auto& label = (*labels)[iVtx]; + const auto multiplicity = static_cast(vertex.getNContributors()); + ++totalFound; + + if (!isTrueVertexLabel(label)) { + ++fakeFound; + fillMultiplicityHistogram(hRecoMultiplicityFake, multiplicity); + continue; + } + + ++trueFound; + const auto eventID = label.getEventID(); + uniqueTrueLabelsReco.insert(eventID); + fillMultiplicityHistogram(hRecoMultiplicityTrue, multiplicity); + + const auto truthIt = findableTruths.find(eventID); + if (truthIt == findableTruths.end()) { + continue; + } + + uniqueFindableTruthFound.insert(eventID); + const auto purity = (hasPurityBranch && purities != nullptr) ? (*purities)[iVtx] : -1.f; + const auto bestIt = bestRecoByTruth.find(eventID); + if (bestIt == bestRecoByTruth.end() || isBetterReco(vertex, purity, bestIt->second.vertex, bestIt->second.purity)) { + bestRecoByTruth[eventID] = BestRecoInfo{vertex, purity}; + } + } + } + + tracFileHandle->Close(); + delete tracFileHandle; + + findable += findableTruths.size(); + uniqueTrueReco += uniqueTrueLabelsReco.size(); + uniqueFindableFound += uniqueFindableTruthFound.size(); + + for (const auto eventID : uniqueFindableTruthFound) { + const auto truthIt = findableTruths.find(eventID); + if (truthIt != findableTruths.end()) { + fillMultiplicityHistogram(hTruthMultiplicityFound, truthIt->second.multiplicity); + } + } + + for (const auto& [eventID, reco] : bestRecoByTruth) { + const auto truthIt = findableTruths.find(eventID); + if (truthIt == findableTruths.end()) { + continue; + } + const auto dx = reco.vertex.getX() - truthIt->second.x; + const auto dy = reco.vertex.getY() - truthIt->second.y; + const auto dz = reco.vertex.getZ() - truthIt->second.z; + hDx->Fill(dx); + hDy->Fill(dy); + hDz->Fill(dz); + if (reco.vertex.getSigmaX() > 0.f) { + const auto pullX = dx / reco.vertex.getSigmaX(); + hPullX->Fill(pullX); + hPullXByMult[getMultiplicityCategory(reco.vertex.getNContributors()) - 1]->Fill(pullX); + sumSigmaX += reco.vertex.getSigmaX(); + ++sigmaXCount; + } + if (reco.vertex.getSigmaY() > 0.f) { + const auto pullY = dy / reco.vertex.getSigmaY(); + hPullY->Fill(pullY); + hPullYByMult[getMultiplicityCategory(reco.vertex.getNContributors()) - 1]->Fill(pullY); + sumSigmaY += reco.vertex.getSigmaY(); + ++sigmaYCount; + } + if (reco.vertex.getSigmaZ() > 0.f) { + const auto pullZ = dz / reco.vertex.getSigmaZ(); + hPullZ->Fill(pullZ); + hPullZByMult[getMultiplicityCategory(reco.vertex.getNContributors()) - 1]->Fill(pullZ); + sumSigmaZ += reco.vertex.getSigmaZ(); + ++sigmaZCount; + } + } + fs::current_path(cwd); + } + + auto* hTruthMultiplicityEfficiency = static_cast(hTruthMultiplicityFound->Clone("hTruthMultiplicityEfficiency")); + hTruthMultiplicityEfficiency->SetTitle("Unique efficiency vs truth multiplicity;truth multiplicity bin;efficiency"); + hTruthMultiplicityEfficiency->Divide(hTruthMultiplicityFound, hTruthMultiplicityFindable, 1., 1., "B"); + setMultiplicityBinLabels(hTruthMultiplicityEfficiency); + hTruthMultiplicityEfficiency->SetMinimum(0.); + hTruthMultiplicityEfficiency->SetMaximum(1.05); + + auto* hRecoMultiplicityTotal = static_cast(hRecoMultiplicityTrue->Clone("hRecoMultiplicityTotal")); + hRecoMultiplicityTotal->SetTitle("All reconstructed vertices;reco multiplicity bin;vertices"); + hRecoMultiplicityTotal->Add(hRecoMultiplicityFake); + setMultiplicityBinLabels(hRecoMultiplicityTotal); + + auto* hRecoMultiplicityPurity = static_cast(hRecoMultiplicityTrue->Clone("hRecoMultiplicityPurity")); + hRecoMultiplicityPurity->SetTitle("Purity vs reconstructed multiplicity;reco multiplicity bin;purity"); + hRecoMultiplicityPurity->Divide(hRecoMultiplicityTrue, hRecoMultiplicityTotal, 1., 1., "B"); + setMultiplicityBinLabels(hRecoMultiplicityPurity); + hRecoMultiplicityPurity->SetMinimum(0.); + hRecoMultiplicityPurity->SetMaximum(1.05); + + const auto duplicates = trueFound >= uniqueTrueReco ? (trueFound - uniqueTrueReco) : 0UL; + + const double uniqueEfficiency = findable > 0 ? static_cast(uniqueFindableFound) / findable : 0.; + const double purity = totalFound > 0 ? static_cast(trueFound) / totalFound : 0.; + const double fakeRate = totalFound > 0 ? static_cast(fakeFound) / totalFound : 0.; + const double duplicateRate = trueFound > 0 ? static_cast(duplicates) / trueFound : 0.; + const double f1 = (uniqueEfficiency + purity) > 0. ? 2. * uniqueEfficiency * purity / (uniqueEfficiency + purity) : 0.; + + const auto dxFit = fitGaussianCore(hDx, "fitDx"); + const auto dyFit = fitGaussianCore(hDy, "fitDy"); + const auto dzFit = fitGaussianCore(hDz, "fitDz"); + const auto pullXFit = fitGaussianCore(hPullX, "fitPullX"); + const auto pullYFit = fitGaussianCore(hPullY, "fitPullY"); + const auto pullZFit = fitGaussianCore(hPullZ, "fitPullZ"); + std::array pullXByMultFit{}; + std::array pullYByMultFit{}; + std::array pullZByMultFit{}; + for (int i = 0; i < NMultiplicityBins; ++i) { + const auto fitX = std::string("fitPullX_") + std::to_string(i + 1); + const auto fitY = std::string("fitPullY_") + std::to_string(i + 1); + const auto fitZ = std::string("fitPullZ_") + std::to_string(i + 1); + pullXByMultFit[i] = fitGaussianCore(hPullXByMult[i], fitX.c_str()); + pullYByMultFit[i] = fitGaussianCore(hPullYByMult[i], fitY.c_str()); + pullZByMultFit[i] = fitGaussianCore(hPullZByMult[i], fitZ.c_str()); + } + + std::printf("\nVertex validation summary\n"); + std::printf(" findable truth vertices : %zu\n", findable); + std::printf(" total reconstructed vertices : %zu\n", totalFound); + std::printf(" true reconstructed vertices : %zu\n", trueFound); + std::printf(" fake reconstructed vertices : %zu\n", fakeFound); + std::printf(" unique true labels (all) : %zu\n", uniqueTrueReco); + std::printf(" unique findable truth found : %zu\n", uniqueFindableFound); + std::printf(" unique efficiency : %.5f\n", uniqueEfficiency); + std::printf(" purity : %.5f\n", purity); + std::printf(" fake rate : %.5f\n", fakeRate); + std::printf(" duplicate rate : %.5f\n", duplicateRate); + std::printf(" F1(purity,efficiency) : %.5f\n", f1); + std::printf(" mean reported sigma x/y/z : %.6g / %.6g / %.6g cm\n", + sigmaXCount > 0 ? sumSigmaX / sigmaXCount : 0., + sigmaYCount > 0 ? sumSigmaY / sigmaYCount : 0., + sigmaZCount > 0 ? sumSigmaZ / sigmaZCount : 0.); + + if (dxFit.valid) { + std::printf(" x residual Gaussian: mean=%.6g cm sigma=%.6g cm\n", dxFit.mean, dxFit.sigma); + } + if (dyFit.valid) { + std::printf(" y residual Gaussian: mean=%.6g cm sigma=%.6g cm\n", dyFit.mean, dyFit.sigma); + } + if (dzFit.valid) { + std::printf(" z residual Gaussian: mean=%.6g cm sigma=%.6g cm\n", dzFit.mean, dzFit.sigma); + } + if (pullXFit.valid) { + std::printf(" x pull Gaussian : mean=%.6g sigma=%.6g\n", pullXFit.mean, pullXFit.sigma); + } + if (pullYFit.valid) { + std::printf(" y pull Gaussian : mean=%.6g sigma=%.6g\n", pullYFit.mean, pullYFit.sigma); + } + if (pullZFit.valid) { + std::printf(" z pull Gaussian : mean=%.6g sigma=%.6g\n", pullZFit.mean, pullZFit.sigma); + } + printGaussianByMultiplicity(pullXByMultFit, "x pull Gaussian by reconstructed multiplicity"); + printGaussianByMultiplicity(pullYByMultFit, "y pull Gaussian by reconstructed multiplicity"); + printGaussianByMultiplicity(pullZByMultFit, "z pull Gaussian by reconstructed multiplicity"); + + printBinnedFractions(hTruthMultiplicityFound, hTruthMultiplicityFindable, "Efficiency vs truth multiplicity"); + printBinnedFractions(hRecoMultiplicityTrue, hRecoMultiplicityTotal, "Purity vs reconstructed multiplicity"); + + auto* cValidation = new TCanvas("cVertexValidation", "Vertex validation summary", 1800, 1000); + cValidation->Divide(3, 2); + + cValidation->cd(1); + gPad->SetMargin(0.05, 0.05, 0.05, 0.05); + auto* summary = new TPaveText(0.02, 0.02, 0.98, 0.98, "NDC"); + summary->SetBorderSize(0); + summary->SetFillColor(0); + summary->SetTextAlign(12); + summary->SetTextFont(42); + char line[256]; + std::snprintf(line, sizeof(line), "Findable truth vertices : %zu", findable); + summary->AddText(line); + std::snprintf(line, sizeof(line), "Total reconstructed : %zu", totalFound); + summary->AddText(line); + std::snprintf(line, sizeof(line), "True reconstructed : %zu", trueFound); + summary->AddText(line); + std::snprintf(line, sizeof(line), "Fake reconstructed : %zu", fakeFound); + summary->AddText(line); + summary->AddText(""); + std::snprintf(line, sizeof(line), "Unique truth found : %zu", uniqueFindableFound); + summary->AddText(line); + std::snprintf(line, sizeof(line), "Unique efficiency : %.5f", uniqueEfficiency); + summary->AddText(line); + std::snprintf(line, sizeof(line), "Purity : %.5f", purity); + summary->AddText(line); + std::snprintf(line, sizeof(line), "Fake rate : %.5f", fakeRate); + summary->AddText(line); + std::snprintf(line, sizeof(line), "Duplicate rate : %.5f", duplicateRate); + summary->AddText(line); + std::snprintf(line, sizeof(line), "F1 : %.5f", f1); + summary->AddText(line); + std::snprintf(line, sizeof(line), "mean sigma x/y/z cm : %.3g / %.3g / %.3g", + sigmaXCount > 0 ? sumSigmaX / sigmaXCount : 0., + sigmaYCount > 0 ? sumSigmaY / sigmaYCount : 0., + sigmaZCount > 0 ? sumSigmaZ / sigmaZCount : 0.); + summary->AddText(line); + summary->AddText(""); + if (dxFit.valid) { + std::snprintf(line, sizeof(line), "dx fit mean/sigma cm : %.3g / %.3g", dxFit.mean, dxFit.sigma); + summary->AddText(line); + } + if (dyFit.valid) { + std::snprintf(line, sizeof(line), "dy fit mean/sigma cm : %.3g / %.3g", dyFit.mean, dyFit.sigma); + summary->AddText(line); + } + if (dzFit.valid) { + std::snprintf(line, sizeof(line), "dz fit mean/sigma cm : %.3g / %.3g", dzFit.mean, dzFit.sigma); + summary->AddText(line); + } + if (pullXFit.valid) { + std::snprintf(line, sizeof(line), "pull x sigma : %.3g", pullXFit.sigma); + summary->AddText(line); + } + if (pullYFit.valid) { + std::snprintf(line, sizeof(line), "pull y sigma : %.3g", pullYFit.sigma); + summary->AddText(line); + } + if (pullZFit.valid) { + std::snprintf(line, sizeof(line), "pull z sigma : %.3g", pullZFit.sigma); + summary->AddText(line); + } + summary->Draw(); + + cValidation->cd(2); + gPad->SetGridy(); + hTruthMultiplicityEfficiency->Draw("hist e1"); + + cValidation->cd(3); + gPad->SetGridy(); + const auto maxReco = std::max(hRecoMultiplicityTrue->GetMaximum(), hRecoMultiplicityFake->GetMaximum()); + hRecoMultiplicityTrue->SetMaximum(1.2 * std::max(1., maxReco)); + hRecoMultiplicityTrue->Draw("hist e1"); + hRecoMultiplicityFake->Draw("hist e1 same"); + auto hRecoMultiplicitySum = (TH1D*)hRecoMultiplicityTrue->Clone("hRecoMultiplicitySum"); + hRecoMultiplicitySum->Add(hRecoMultiplicityFake); + setHistogramStyle(hRecoMultiplicitySum, kBlack, 23); + hRecoMultiplicitySum->Draw("hist e1 same"); + { + auto* legend = new TLegend(0.58, 0.75, 0.88, 0.88); + legend->SetBorderSize(0); + legend->AddEntry(hRecoMultiplicityTrue, "true", "lep"); + legend->AddEntry(hRecoMultiplicityFake, "fake", "lep"); + legend->AddEntry(hRecoMultiplicitySum, "sum", "lep"); + legend->Draw(); + } + + cValidation->cd(4); + gPad->SetGridy(); + hRecoMultiplicityPurity->Draw("hist e1"); + + cValidation->cd(5); + gPad->SetGridy(); + auto* hDxNorm = makeNormalizedCopy(hDx, "hDxNorm", "Matched vertex residuals;residual (cm);normalized entries"); + auto* hDyNorm = makeNormalizedCopy(hDy, "hDyNorm", "Matched vertex residuals;residual (cm);normalized entries"); + auto* hDzNorm = makeNormalizedCopy(hDz, "hDzNorm", "Matched vertex residuals;residual (cm);normalized entries"); + const auto maxResidual = std::max({hDxNorm->GetMaximum(), hDyNorm->GetMaximum(), hDzNorm->GetMaximum()}); + hDzNorm->SetMaximum(1.2 * std::max(1., maxResidual)); + hDzNorm->Draw("hist"); + hDxNorm->Draw("hist same"); + hDyNorm->Draw("hist same"); + { + auto* legend = new TLegend(0.62, 0.72, 0.88, 0.88); + legend->SetBorderSize(0); + legend->AddEntry(hDxNorm, "dx", "l"); + legend->AddEntry(hDyNorm, "dy", "l"); + legend->AddEntry(hDzNorm, "dz", "l"); + legend->Draw(); + } + + cValidation->cd(6); + gPad->SetGridy(); + auto* hPullXNorm = makeNormalizedCopy(hPullX, "hPullXNorm", "Matched vertex pulls;pull;normalized entries"); + auto* hPullYNorm = makeNormalizedCopy(hPullY, "hPullYNorm", "Matched vertex pulls;pull;normalized entries"); + auto* hPullZNorm = makeNormalizedCopy(hPullZ, "hPullZNorm", "Matched vertex pulls;pull;normalized entries"); + const auto maxPull = std::max({hPullXNorm->GetMaximum(), hPullYNorm->GetMaximum(), hPullZNorm->GetMaximum()}); + hPullZNorm->SetMaximum(1.2 * std::max(1., maxPull)); + hPullZNorm->Draw("hist"); + hPullXNorm->Draw("hist same"); + hPullYNorm->Draw("hist same"); + { + auto* legend = new TLegend(0.62, 0.72, 0.88, 0.88); + legend->SetBorderSize(0); + legend->AddEntry(hPullXNorm, "pull x", "l"); + legend->AddEntry(hPullYNorm, "pull y", "l"); + legend->AddEntry(hPullZNorm, "pull z", "l"); + legend->Draw(); + } + + cValidation->cd(); + cValidation->Update(); + cValidation->SaveAs("checkSeeding.pdf"); +} diff --git a/Detectors/ITSMFT/ITS/macros/test/CheckStaggering.C b/Detectors/ITSMFT/ITS/macros/test/CheckStaggering.C new file mode 100644 index 0000000000000..11ebcbbb1b1f1 --- /dev/null +++ b/Detectors/ITSMFT/ITS/macros/test/CheckStaggering.C @@ -0,0 +1,527 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DetectorsBase/Propagator.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITS/TrackITS.h" +#include "DataFormatsITS/Vertex.h" +#include "DataFormatsITS/TimeEstBC.h" +#include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/LHCConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "ReconstructionDataFormats/Vertex.h" +#include "DetectorsVertexing/SVertexHypothesis.h" +#include "DCAFitter/DCAFitterN.h" +#endif + +constexpr const char* tracFile = "o2trac_its.root"; +constexpr const char* clsFile = "o2clus_its.root"; + +struct PairCandidate { + int posIdx; + int negIdx; + double dca; + double mass; +}; + +std::vector findDirs(const std::string&); + +void CheckStaggering(int runNumber, int max = -1, const std::string& dir = "") +{ + gStyle->SetOptStat(0); + auto dirs = findDirs(dir); + printf("Will iterate over %zu input dirs", dirs.size()); + if (dirs.empty()) { + printf("No input found"); + return; + } + if (max > 0 && (int)dirs.size() > max) { + std::random_device rd; + std::mt19937 g(rd()); + std::shuffle(dirs.begin(), dirs.end(), g); + dirs.resize(max); + printf("restricting to %ddirs", max); + } + + auto& ccdbmgr = o2::ccdb::BasicCCDBManager::instance(); + ccdbmgr.setURL("https://alice-ccdb.cern.ch"); + auto runDuration = ccdbmgr.getRunDuration(runNumber); + auto tRun = runDuration.first + ((runDuration.second - runDuration.first) / 2); // time stamp for the middle of the run duration + ccdbmgr.setTimestamp(tRun); + printf("Run %d has TS %ld", runNumber, tRun); + auto geoAligned = ccdbmgr.get("GLO/Config/GeometryAligned"); + auto magField = ccdbmgr.get("GLO/Config/GRPMagField"); + auto grpLHC = ccdbmgr.get("GLO/Config/GRPLHCIF"); + auto bcFill = grpLHC->getBunchFilling(); + bcFill.print(-1); + const o2::base::MatLayerCylSet* matLut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdbmgr.get("GLO/Param/MatLUT")); + o2::base::Propagator::initFieldFromGRP(magField); + auto prop = o2::base::Propagator::Instance(); + prop->setMatLUT(matLut); + const float bz = prop->getNominalBz(); + + auto hNTrkCls = new TH1D("hNTrkCls", "Number of cluster per track;nCls;entries", 4, 3.5, 7.5); + std::array hTrkTS{nullptr}; + for (int i{0}; i < 5; ++i) { + hTrkTS[i] = new TH1D(Form("hTrkTS_%d", i), Form("track time t0 (%s);t0 (BC)", i == 0 ? "all" : Form("NCls=%d", 3 + i)), o2::constants::lhc::LHCMaxBunches, 0, o2::constants::lhc::LHCMaxBunches); + } + auto hTrkTSE = new TH1D("hTrkTSE", "assigned time errors; tE (BC)", 198, -0.5, 198 - 0.5); + + // K0 && Phi-Meson + const float mMinITSPt{0.15}; + // + const int phiMinNCls{7}; + const float phiMaxDCAR2MVTX{0.05}; // max distance to mean vtx + auto hPhiMeson = new TH1D("hPhiMeson", "#phi meson;mass (GeV/c^{2})", 200, 0.96, 1.1); + auto hPhiMesonBkg = new TH1D("hPhiMesonBkg", "#phi meson background;mass (GeV/c^{2})", 200, 0.96, 1.1); + + const int mK0MinNCls{7}; + const float mK0minCosPAXYMeanVertex = 0.98; + const float mK0MaxDCAXY2ToMeanVertex = 0.2; + const float mK0MaxTgl2V0 = 1; + const float mK0MinPt2V0 = 0.3; + const float mK0MinCosPA = 0.999; + o2::vertexing::DCAFitterN<2> k0Ft; + k0Ft.setBz(bz); + k0Ft.setPropagateToPCA(true); // After finding the vertex, propagate tracks to the DCA. This is default anyway + k0Ft.setMaxR(30); + k0Ft.setMaxDZIni(0.1); + k0Ft.setMaxDXYIni(0.1); + k0Ft.setMinParamChange(1e-3); + k0Ft.setMinRelChi2Change(0.9); + k0Ft.setMaxChi2(5); + k0Ft.setUseAbsDCA(true); + auto hK0 = new TH1D("hK0", "K0;mass (GeV/c^{2})", 100, 0.4, 0.6); + o2::vertexing::SVertexHypothesis k0Hyp; + const float k0Par[] = {0., 20, 0., 5.0, 0.0, 1.09004e-03, 2.62291e-04, 8.93179e-03, 2.83121}; + k0Hyp.set(o2::track::PID::K0, o2::track::PID::Pion, o2::track::PID::Pion, k0Par, bz); + + auto hVtxXY = new TH2F("hVtxXY", "seeding vertices XY", 200, -0.3, 0.3, 200, -0.3, 0.3); + auto hVtxZ = new TH1F("hVtxZ", "seeding vertices Z", 200, -16, 16); + auto hVtxNCont = new TH1F("hVtxNCont", "seeding vertices contributors", 100, 0, 100); + auto hVtxZNCont = new TProfile("hVtxZNCont", "seeding vertices z-contributors", 200, -16, 16); + auto hVtxCls = new TProfile("hVtxCls", ";Cls/TF;Cls/Vtx", 2000, 600000, 900000); + auto hVtxTS = new TH1D("hVtxTS", "vtx time t0;t0 (BC)", o2::constants::lhc::LHCMaxBunches, 0, o2::constants::lhc::LHCMaxBunches); + + const float minVtxWeight{5}; + float meanVtxWeight{0}; + o2::dataformats::VertexBase meanVtx; + auto accountVtx = [&](o2::its::Vertex const& vtx) { + const float w = vtx.getNContributors(); + if (w >= minVtxWeight) { + meanVtx.setX((meanVtx.getX() * meanVtxWeight + vtx.getX() * w) / (meanVtxWeight + w)); + meanVtx.setY((meanVtx.getY() * meanVtxWeight + vtx.getY() * w) / (meanVtxWeight + w)); + meanVtxWeight += w; + } + }; + + std::vector trkArr, *trkArrPtr{&trkArr}; + std::vector vtxArr, *vtxArrPtr{&vtxArr}; + std::array*, 7> clsArr{nullptr}; + for (size_t iDir{0}; iDir < dirs.size(); ++iDir) { + int progress = static_cast((iDir + 1) * 100 / dirs.size()); + printf("\rProgress: ["); + int barWidth = 50; + int pos = barWidth * progress / 100; + for (int j = 0; j < barWidth; ++j) { + if (j < pos) { + printf("="); + } else if (j == pos) { + printf(">"); + } else { + printf(" "); + } + } + printf("] %d%%", progress); + fflush(stdout); + + const auto& d = dirs[iDir]; + auto fTrks = TFile::Open((d / tracFile).c_str()); + auto fCls = TFile::Open((d / clsFile).c_str()); + if (!fTrks || !fCls || fTrks->IsZombie() || fCls->IsZombie()) { + continue; + } + auto tTrks = fTrks->Get("o2sim"); + auto tCls = fCls->Get("o2sim"); + if (!tTrks || !tCls) { + continue; + } + + tTrks->SetBranchAddress("ITSTrack", &trkArrPtr); + tTrks->SetBranchAddress("Vertices", &vtxArrPtr); + if (tCls->GetBranchStatus("ITSClusterComp")) { + tCls->SetBranchAddress("ITSClusterComp", &clsArr[0]); + } else { + for (int i{0}; i < 7; ++i) { + tCls->SetBranchAddress(Form("ITSClusterComp_%d", i), &clsArr[i]); + } + } + + for (int iTF{0}; tTrks->LoadTree(iTF) >= 0; ++iTF) { + tTrks->GetEntry(iTF); + tCls->GetEntry(iTF); + + size_t ncls = 0; + for (int i{0}; i < 7; ++i) { + if (clsArr[i]) { + ncls += clsArr[i]->size(); + } + } + + // for each TF built pool of positive and negaitve tracks + std::vector posPool, negPool; + + for (const auto& trk : trkArr) { + hNTrkCls->Fill(trk.getNClusters()); + hTrkTS[0]->Fill(std::fmod(trk.getTimeStamp().getTimeStamp(), o2::constants::lhc::LHCMaxBunches)); + hTrkTS[trk.getNClusters() - 3]->Fill(std::fmod(trk.getTimeStamp().getTimeStamp(), o2::constants::lhc::LHCMaxBunches)); + hTrkTSE->Fill(trk.getTimeStamp().getTimeStampError()); + + if (trk.getPt() > mMinITSPt) { + if (trk.getCharge() > 0) { + posPool.push_back(&trk); + } else { + negPool.push_back(&trk); + } + } + } + + for (const auto& vtx : vtxArr) { + hVtxXY->Fill(vtx.getX(), vtx.getY()); + hVtxZ->Fill(vtx.getZ()); + hVtxNCont->Fill(vtx.getNContributors()); + hVtxZNCont->Fill(vtx.getZ(), vtx.getNContributors()); + hVtxTS->Fill(vtx.getTimeStamp().getTimeStamp()); + accountVtx(vtx); + } + hVtxCls->Fill(ncls, (float)ncls / (float)vtxArr.size()); + + std::vector k0Cands; + for (int iPos{0}; iPos < (int)posPool.size(); ++iPos) { + const auto pos = posPool[iPos]; + for (int iNeg{0}; iNeg < (int)negPool.size(); ++iNeg) { + const auto neg = negPool[iNeg]; + bool overlap = std::abs(pos->getTimeStamp().getTimeStamp() - neg->getTimeStamp().getTimeStamp()) <= (pos->getTimeStamp().getTimeStampError() + neg->getTimeStamp().getTimeStampError()); + if (!overlap) { + continue; + } + + // phi-meson + if (pos->getNClusters() >= phiMinNCls && neg->getNClusters() >= phiMinNCls) { + o2::dataformats::DCA posDCA, negDCA; + o2::track::TrackParCov posPhi = *pos; + posPhi.setPID(o2::track::PID::Kaon); + o2::track::TrackParCov negPhi = *neg; + negPhi.setPID(o2::track::PID::Kaon); + if (prop->propagateToDCA(meanVtx, posPhi, bz, 2.0, o2::base::Propagator::MatCorrType::USEMatCorrLUT, &posDCA) && prop->propagateToDCA(meanVtx, negPhi, bz, 2.0, o2::base::Propagator::MatCorrType::USEMatCorrLUT, &negDCA)) { + if (posDCA.getR2() < phiMaxDCAR2MVTX && negDCA.getR2() < phiMaxDCAR2MVTX) { + std::array pP{}, pN{}; + posPhi.getPxPyPzGlo(pP); + negPhi.getPxPyPzGlo(pN); + TLorentzVector p1, p2; + p1.SetXYZM(pP[0], pP[1], pP[2], posPhi.getPID().getMass()); + p2.SetXYZM(pN[0], pN[1], pN[2], negPhi.getPID().getMass()); + TLorentzVector mother = p1 + p2; + hPhiMeson->Fill(mother.M()); + // rotate on daughter track to estimate background + for (int i{0}; i < 10; ++i) { + double theta = gRandom->Uniform(165.f, 195.f) * TMath::DegToRad(); + double pxN = pN[0] * cos(theta) - pN[1] * sin(theta); + double pyN = pN[0] * sin(theta) + pN[1] * cos(theta); + double pxP = pP[0] * cos(-theta) - pP[1] * sin(-theta); + double pyP = pP[0] * sin(-theta) + pP[1] * cos(-theta); + p1.SetXYZM(pxP, pyP, pP[2], posPhi.getPID().getMass()); + p2.SetXYZM(pxN, pyN, pN[2], negPhi.getPID().getMass()); + mother = p1 + p2; + hPhiMesonBkg->Fill(mother.M()); + } + } + } + } + // K0 + if (pos->getNClusters() >= mK0MinNCls && neg->getNClusters() >= mK0MinNCls) { + o2::track::TrackParCov posPion = *pos; + posPion.setPID(o2::track::PID::Pion); + o2::track::TrackParCov negPion = *neg; + negPion.setPID(o2::track::PID::Pion); + int ncand = k0Ft.process(posPion, negPion); + const int cand = 0; + if (ncand) { + const auto& v0XYZ = k0Ft.getPCACandidate(); + float dxv0 = v0XYZ[0] - meanVtx.getX(), dyv0 = v0XYZ[1] - meanVtx.getY(), r2v0 = dxv0 * dxv0 + dyv0 * dyv0; + if (!k0Ft.isPropagateTracksToVertexDone(cand) && !k0Ft.propagateTracksToVertex(cand)) { + continue; + } + const auto& trPProp = k0Ft.getTrack(0, cand); + const auto& trNProp = k0Ft.getTrack(1, cand); + std::array pP{}, pN{}; + trPProp.getPxPyPzGlo(pP); + trNProp.getPxPyPzGlo(pN); + // estimate DCA of neutral V0 track to beamline: straight line with parametric equation + // x = X0 + pV0[0]*t, y = Y0 + pV0[1]*t reaches DCA to beamline (Xv, Yv) at + // t = -[ (x0-Xv)*pV0[0] + (y0-Yv)*pV0[1]) ] / ( pT(pV0)^2 ) + // Similar equation for 3D distance involving pV0[2] + std::array pV0 = {pP[0] + pN[0], pP[1] + pN[1], pP[2] + pN[2]}; + float pt2V0 = pV0[0] * pV0[0] + pV0[1] * pV0[1], prodXYv0 = dxv0 * pV0[0] + dyv0 * pV0[1], tDCAXY = prodXYv0 / pt2V0; + if (pt2V0 < mK0MinPt2V0) { // pt cut + continue; + } + if (pV0[2] * pV0[2] / pt2V0 > mK0MaxTgl2V0) { // tgLambda cut + continue; + } + float dcaX = dxv0 - pV0[0] * tDCAXY, dcaY = dyv0 - pV0[1] * tDCAXY, dca2 = dcaX * dcaX + dcaY * dcaY; + float cosPAXY = prodXYv0 / std::sqrt(r2v0 * pt2V0); + if (dca2 > mK0MaxDCAXY2ToMeanVertex || cosPAXY < mK0minCosPAXYMeanVertex) { + continue; + } + float p2V0 = pt2V0 + pV0[2] * pV0[2], ptV0 = std::sqrt(pt2V0); + 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]; + if (!k0Hyp.check(p2Pos, p2Neg, p2V0, ptV0)) { + continue; + } + + float bestCosPA = mK0MinCosPA; + bool candFound = false; + for (const auto& vtx : vtxArr) { + if (vtx.getNContributors() > minVtxWeight) { + const auto vtxT = vtx.getTimeStamp().makeSymmetrical(); + bool overlapPos = std::abs(pos->getTimeStamp().getTimeStamp() - vtxT.getTimeStamp()) <= (pos->getTimeStamp().getTimeStampError() + vtxT.getTimeStampError()); + bool overlapNeg = std::abs(neg->getTimeStamp().getTimeStamp() - vtxT.getTimeStamp()) <= (neg->getTimeStamp().getTimeStampError() + vtxT.getTimeStampError()); + if (overlapPos && overlapNeg) { + float dx = v0XYZ[0] - vtx.getX(), dy = v0XYZ[1] - vtx.getY(), dz = v0XYZ[2] - vtx.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) { + bestCosPA = cosPA; + candFound = true; + } + } + } + } + if (candFound) { + TLorentzVector p1, p2; + p1.SetXYZM(pP[0], pP[1], pP[2], posPion.getPID().getMass()); + p2.SetXYZM(pN[0], pN[1], pN[2], negPion.getPID().getMass()); + TLorentzVector mother = p1 + p2; + double mass = mother.M(); + k0Cands.emplace_back(iPos, iNeg, k0Ft.getChi2AtPCACandidate(cand), mass); + } + } + } + } + } + + // disambiguiate candidates by using the smallest DCA one + std::sort(k0Cands.begin(), k0Cands.end(), [](const auto& a, const auto& b) { return a.dca < b.dca; }); + std::vector posUsed(posPool.size(), false); + std::vector negUsed(negPool.size(), false); + for (const auto& c : k0Cands) { + if (!posUsed[c.posIdx] && !negUsed[c.negIdx]) { + posUsed[c.posIdx] = true; + negUsed[c.negIdx] = true; + hK0->Fill(c.mass); + } + } + } + + fTrks->Close(); + fCls->Close(); + } + + auto drawBCPattern = [&]() { + gPad->Update(); + // draw BC pattern + double ymin = gPad->GetUymin(); + double ymax = gPad->GetUymax(); + auto interactingBC = bcFill.getPattern(); + TLine* lastLine{nullptr}; + for (int iBC{0}; iBC < (int)interactingBC.size(); ++iBC) { + if (interactingBC.test(iBC)) { + TLine* line = new TLine(iBC, ymin, iBC, ymax); + line->SetLineColor(kRed); + line->SetLineWidth(1); + line->SetLineStyle(kDashed); + line->Draw(); + lastLine = line; + } + } + return lastLine; + }; + + { + TFile out(Form("check_%d.root", runNumber), "RECREATE"); + out.WriteTObject(hNTrkCls); + for (int i{0}; i < 5; ++i) { + out.WriteTObject(hTrkTS[i]); + } + out.WriteTObject(hTrkTSE); + out.WriteTObject(hPhiMeson); + out.WriteTObject(hPhiMesonBkg); + out.WriteTObject(hK0); + out.WriteTObject(hVtxXY); + out.WriteTObject(hVtxZ); + out.WriteTObject(hVtxNCont); + out.WriteTObject(hVtxZNCont); + out.WriteTObject(hVtxTS); + out.WriteTObject(hVtxCls); + } + + // fitK0(hK0, runNumber); + // fitPhiMeson(hPhiMeson, runNumber); + { + auto c = new TCanvas(); + hNTrkCls->Draw(); + c->Draw(); + c->SaveAs(Form("trk_%d.pdf", runNumber)); + } + { + auto c = new TCanvas(); + c->Divide(3, 2); + for (int i{0}; i < 5; ++i) { + c->cd(i + 1); + hTrkTS[i]->Draw(); + auto lastLine = drawBCPattern(); + if (i == 0) { + auto leg = new TLegend(0.6, 0.6, 0.9, 0.9); + leg->AddEntry(lastLine, "Interacting BCs", "l"); + leg->AddEntry(hTrkTS[i], "Track timestamp"); + leg->Draw(); + } + } + c->cd(6); + hTrkTSE->Draw(); + c->Draw(); + c->SaveAs(Form("time_%d.pdf", runNumber)); + } + { + auto c = new TCanvas(); + c->Divide(2, 1); + { + c->cd(1); + hPhiMeson->Draw(); + gPad->Update(); + double ymin = gPad->GetUymin(); + double ymax = gPad->GetUymax(); + const float mass = 1.019461; + TLine* line = new TLine(mass, ymin, mass, ymax); + line->SetLineColor(kRed); + line->SetLineWidth(1); + line->SetLineStyle(kDashed); + line->Draw(); + } + { + c->cd(2); + hK0->Draw(); + gPad->Update(); + double ymin = gPad->GetUymin(); + double ymax = gPad->GetUymax(); + const float mass = 0.497611; + TLine* line = new TLine(mass, ymin, mass, ymax); + line->SetLineColor(kRed); + line->SetLineWidth(1); + line->SetLineStyle(kDashed); + line->Draw(); + } + c->Draw(); + c->SaveAs(Form("mass_%d.pdf", runNumber)); + } + { + auto c = new TCanvas(); + c->Divide(3, 2); + { + c->cd(1); + hVtxXY->Draw("col"); + } + { + c->cd(2); + hVtxZ->Draw(); + } + { + c->cd(3); + hVtxNCont->Draw(); + } + { + c->cd(4); + hVtxZNCont->Draw(); + } + { + c->cd(5); + hVtxCls->Draw(); + } + { + c->cd(6); + hVtxTS->Draw(); + auto lastLine = drawBCPattern(); + auto leg = new TLegend(0.6, 0.6, 0.9, 0.9); + leg->AddEntry(lastLine, "Interacting BCs", "l"); + leg->AddEntry(hVtxTS, "Track timestamp"); + leg->Draw(); + } + c->Draw(); + c->SaveAs(Form("vertex_%d.pdf", runNumber)); + } +} + +std::vector findDirs(const std::string& roots) +{ + std::filesystem::path root; + if (roots.empty()) { + root = std::filesystem::current_path(); + } else { + root = roots; + } + namespace fs = std::filesystem; + std::vector result; + auto has_files = [](const fs::path& dir) { + auto s = dir / tracFile; + return fs::exists(dir / tracFile) && fs::exists(dir / clsFile) && + fs::is_regular_file(dir / tracFile) && fs::is_regular_file(dir / clsFile); + }; + if (fs::is_directory(root) && has_files(root)) { + result.push_back(root); + return result; + } + for (const auto& entry : fs::recursive_directory_iterator(root)) { + if (!entry.is_directory()) { + continue; + } + const fs::path dir = entry.path(); + if (has_files(dir)) { + result.push_back(dir); + } + } + return result; +} diff --git a/Detectors/ITSMFT/ITS/macros/test/CheckTracksCA.C b/Detectors/ITSMFT/ITS/macros/test/CheckTracksCA.C index 7c128ce34d538..e185be83a389f 100644 --- a/Detectors/ITSMFT/ITS/macros/test/CheckTracksCA.C +++ b/Detectors/ITSMFT/ITS/macros/test/CheckTracksCA.C @@ -21,16 +21,21 @@ #include #include #include +#include #include #include #include #include #include +#include +#include +#include #include "ITSBase/GeometryTGeo.h" #include "SimulationDataFormat/MCEventHeader.h" #include "DetectorsBase/Propagator.h" #include "SimulationDataFormat/TrackReference.h" +#include "SimulationDataFormat/O2DatabasePDG.h" #include "SimulationDataFormat/MCTrack.h" #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" @@ -41,6 +46,19 @@ using namespace std; +// chi2 PDF with amplitude A, degrees of freedom k, scale s +Double_t chi2_pdf(Double_t* x, Double_t* par) +{ + const Double_t xx = x[0]; + const Double_t A = par[0]; + const Double_t k = par[1]; + const Double_t s = par[2]; + if (xx <= 0.0 || k <= 0.0 || s <= 0.0) + return 0.0; + const Double_t coef = 1.0 / (TMath::Power(2.0 * s, k * 0.5) * TMath::Gamma(k * 0.5)); + return A * coef * TMath::Power(xx, k * 0.5 - 1.0) * TMath::Exp(-xx / (2.0 * s)); +} + struct ParticleInfo { int event; int pdg; @@ -60,11 +78,15 @@ struct ParticleInfo { bool isPrimary = 0u; unsigned char storedStatus = 2; /// not stored = 2, fake = 1, good = 0 o2::its::TrackITS track; + o2::MCTrack mcTrack; }; #pragma link C++ class ParticleInfo + ; -void CheckTracksCA(bool doFakeClStud = false, +void CheckTracksCA(bool doEffStud = true, + bool doFakeClStud = false, + bool doPullStud = false, + bool createOutput = false, std::string tracfile = "o2trac_its.root", std::string magfile = "o2sim_grp.root", std::string clusfile = "o2clus_its.root", @@ -124,7 +146,10 @@ void CheckTracksCA(bool doFakeClStud = false, info[n].resize(mcArr->size()); hZvertex->Fill(mcEvent->GetZ()); for (unsigned int mcI{0}; mcI < mcArr->size(); ++mcI) { - auto part = mcArr->at(mcI); + const auto part = mcArr->at(mcI); + if (!o2::O2DatabasePDG::Instance()->GetParticle(part.GetPdgCode())) { + continue; + } info[n][mcI].event = n; info[n][mcI].pdg = part.GetPdgCode(); info[n][mcI].pvx = mcEvent->GetX(); @@ -134,6 +159,7 @@ void CheckTracksCA(bool doFakeClStud = false, info[n][mcI].phi = part.GetPhi(); info[n][mcI].eta = part.GetEta(); info[n][mcI].isPrimary = part.isPrimary(); + info[n][mcI].mcTrack = part; } } std::cout << "done." << std::endl; @@ -214,117 +240,108 @@ void CheckTracksCA(bool doFakeClStud = false, 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* numEta = new TH1D("numEta", ";#eta;Number of tracks", 60, -3, 3); - numEta->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) != 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 (!part.isPrimary) { - continue; - } - den->Fill(part.pt); - if (part.isReco) { - num->Fill(part.pt); - numEta->Fill(part.eta); - if (part.isReco > 1) { - for (int _i{0}; _i < part.isReco - 1; ++_i) { - clone->Fill(part.pt); + TFile* file{nullptr}; + if (createOutput) { + file = TFile::Open("CheckTracksCA.root", "recreate"); + } + + if (doEffStud) { + std::cout << "Calculating efficiencies... "; + const 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* numEta = new TH1D("numEta", ";#eta;Number of tracks", 60, -3, 3); + numEta->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) != 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 (!part.isPrimary) { + continue; + } + den->Fill(part.pt); + if (part.isReco) { + num->Fill(part.pt); + numEta->Fill(part.eta); + 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); + 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"); - TCanvas* c2 = new TCanvas; - c2->SetGridx(); - c2->SetGridy(); - hZvertex->DrawClone(); - - 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(); + 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"); + TCanvas* c2 = new TCanvas; + c2->SetGridx(); + c2->SetGridy(); + hZvertex->DrawClone(); + + if (createOutput) { + sum->Write("total"); + fak->Write("singleFake"); + num->Write("efficiency"); + numEta->Write("etaDist"); + multiFak->Write("multiFake"); + clone->Write("clones"); } + std::cout << " done." << std::endl; } - tree.Write(); - sum->Write("total"); - fak->Write("singleFake"); - num->Write("efficiency"); - numEta->Write("etaDist"); - multiFak->Write("multiFake"); - clone->Write("clones"); - file.Close(); - std::cout << " done." << std::endl; ////////////////////// // Fake clusters study if (doFakeClStud) { + std::cout << "Creating fake cluster study... "; std::vector histLength, histLength1Fake, histLengthNoCl, histLength1FakeNoCl; std::vector stackLength, stackLength1Fake; std::vector legends, legends1Fake; @@ -364,10 +381,10 @@ void CheckTracksCA(bool doFakeClStud = false, stackLength1Fake[iH - 4]->Add(histLength1FakeNoCl[iH - 4]); } - for (auto& event : info) { - for (auto& part : event) { + for (const auto& event : info) { + for (const auto& part : event) { int nCl{0}; - for (unsigned int bit{0}; bit < sizeof(pInfo.clusters) * 8; ++bit) { + for (unsigned int bit{0}; bit < sizeof(part.clusters) * 8; ++bit) { nCl += bool(part.clusters & (1 << bit)); } if (nCl < 3) { @@ -409,5 +426,237 @@ void CheckTracksCA(bool doFakeClStud = false, gPad->BuildLegend(); } canvas->SaveAs("fakeClusters.png", "recreate"); + std::cout << " done\n"; + } + + if (doPullStud) { + std::cout << "Creating pull study... "; + const int nBins{30}; + const float xWidth{10}; + // Pulls + auto hYPull = new TH1F("hYPull", "Pull Y", nBins, -xWidth, xWidth); + auto hZPull = new TH1F("hZPull", "Pull Z", nBins, -xWidth, xWidth); + auto hSPhiPull = new TH1F("hSPhiPull", "Pull Sin(Phi)", nBins, -xWidth, xWidth); + auto hTglPull = new TH1F("hTglPull", "Pull Tg(Lambda)", nBins, -xWidth, xWidth); + auto hQoPtPull = new TH1F("hQoPtPull", "Pull Q/Pt", nBins, -xWidth, xWidth); + // Correlation + float maxY2{1e-6}, maxZ2{1e-6}, maxSnp2{2e-6}, maxTgl2{2e-6}, max1Pt2{0.01}; + auto hCorYZ = new TH2F("hCorYZ", ";#sigma_{Z}^{2};#sigma_{Y}^{2}", nBins, 0, maxZ2, nBins, 0, maxY2); + auto hCorYSPhi = new TH2F("hCorYSPhi", ";#sigma_{snp}^{2};#sigma_{Y}^{2}", nBins, 0, maxSnp2, nBins, 0, maxY2); + auto hCorYTgl = new TH2F("hCorYTgl", ";#sigma_{tgl}^{2};#sigma_{Y}^{2}", nBins, 0, maxTgl2, nBins, 0, maxY2); + auto hCorYQoPt = new TH2F("hCorYQoPt", ";#sigma_{Q/Pt}^{2};#sigma_{Y}^{2}", nBins, 0, max1Pt2, nBins, 0, maxY2); + + auto hCorZSPhi = new TH2F("hCorZSPhi", ";#sigma_{snp}^{2};#sigma_{Z}^{2}", nBins, 0, maxSnp2, nBins, 0, maxZ2); + auto hCorZTgl = new TH2F("hCorZTgl", ";#sigma_{tgl}^{2};#sigma_{Z}^{2}", nBins, 0, maxTgl2, nBins, 0, maxZ2); + auto hCorZQoPt = new TH2F("hCorZQoPt", ";#sigma_{Q/Pt}^{2};#sigma_{Z}^{2}", nBins, 0, max1Pt2, nBins, 0, maxZ2); + + auto hCorSPhiTgl = new TH2F("hCorSPhiTgl", ";#sigma_{tgl}^{2};#sigma_{snp}^{2}", nBins, 0, maxTgl2, nBins, 0, maxSnp2); + auto hCorSPhiQoPt = new TH2F("hCorSPhiQoPt", ";#sigma_{Q/Pt}^{2};#sigma_{snp}^{2}", nBins, 0, max1Pt2, nBins, 0, maxSnp2); + + auto hCorTglQoPt = new TH2F("hCorTglQoPt", ";#sigma_{Q/Pt}^{2};#sigma_{tgl}^{2}", nBins, 0, max1Pt2, nBins, 0, maxTgl2); + + auto calcMahalanobisDist = [&](const auto& trk, const auto& mc) -> float { + o2::math_utils::SMatrix> cov; + cov(o2::track::kY, o2::track::kY) = trk.getSigmaY2(); + cov(o2::track::kZ, o2::track::kY) = trk.getSigmaZY(); + cov(o2::track::kZ, o2::track::kZ) = trk.getSigmaZ2(); + cov(o2::track::kSnp, o2::track::kY) = trk.getSigmaSnpY(); + cov(o2::track::kSnp, o2::track::kZ) = trk.getSigmaSnpZ(); + cov(o2::track::kSnp, o2::track::kSnp) = trk.getSigmaSnp2(); + cov(o2::track::kTgl, o2::track::kY) = trk.getSigmaTglY(); + cov(o2::track::kTgl, o2::track::kZ) = trk.getSigmaTglZ(); + cov(o2::track::kTgl, o2::track::kSnp) = trk.getSigmaTglSnp(); + cov(o2::track::kTgl, o2::track::kTgl) = trk.getSigmaTgl2(); + cov(o2::track::kQ2Pt, o2::track::kY) = trk.getSigma1PtY(); + cov(o2::track::kQ2Pt, o2::track::kZ) = trk.getSigma1PtZ(); + cov(o2::track::kQ2Pt, o2::track::kSnp) = trk.getSigma1PtSnp(); + cov(o2::track::kQ2Pt, o2::track::kTgl) = trk.getSigma1PtTgl(); + cov(o2::track::kQ2Pt, o2::track::kQ2Pt) = trk.getSigma1Pt2(); + if (!cov.Invert()) { + return -1.f; + } + o2::math_utils::SVector trkPar(trk.getParams(), o2::track::kNParams), mcPar(mc.getParams(), o2::track::kNParams); + auto res = trkPar - mcPar; + return std::sqrt(ROOT::Math::Similarity(cov, res)); + }; + auto hMahDist = new TH1F("hMahDist", ";Mahalanobis distance;n. entries", 100, 0, 10); + TF1* fchi = new TF1("fchi", chi2_pdf, 0, 6, 3); + fchi->SetParNames("A", "k", "s"); + fchi->SetParameter(0, 1); + fchi->SetParameter(1, 5); + fchi->SetParameter(2, 1); + + for (const auto& event : info) { + for (const auto& part : event) { + if (((part.clusters & 0x7f) != 0x7f) && !part.isPrimary) { + continue; + } + + // prepare mc truth parameters + std::array xyz{(float)part.mcTrack.GetStartVertexCoordinatesX(), (float)part.mcTrack.GetStartVertexCoordinatesY(), (float)part.mcTrack.GetStartVertexCoordinatesZ()}; + std::array pxyz{(float)part.mcTrack.GetStartVertexMomentumX(), (float)part.mcTrack.GetStartVertexMomentumY(), (float)part.mcTrack.GetStartVertexMomentumZ()}; + o2::track::TrackPar mcTrack(xyz, pxyz, TMath::Nint(o2::O2DatabasePDG::Instance()->GetParticle(part.mcTrack.GetPdgCode())->Charge() / 3), false); + if (!mcTrack.rotate(part.track.getAlpha()) || + !o2::base::Propagator::Instance()->propagateTo(mcTrack, part.track.getX())) { + continue; + } + + const float sY = part.track.getSigmaY2(); + const float sZ = part.track.getSigmaZ2(); + const float sSnp = part.track.getSigmaSnp2(); + const float sTgl = part.track.getSigmaTgl2(); + const float s1Pt = part.track.getSigma1Pt2(); + + hYPull->Fill((part.track.getY() - mcTrack.getY()) / std::sqrt(part.track.getSigmaY2())); + hZPull->Fill((part.track.getZ() - mcTrack.getZ()) / std::sqrt(part.track.getSigmaZ2())); + hSPhiPull->Fill((part.track.getSnp() - mcTrack.getSnp()) / std::sqrt(part.track.getSigmaSnp2())); + hTglPull->Fill((part.track.getTgl() - mcTrack.getTgl()) / std::sqrt(part.track.getSigmaTgl2())); + hQoPtPull->Fill((part.track.getQ2Pt() - mcTrack.getQ2Pt()) / std::sqrt(part.track.getSigma1Pt2())); + + hCorYZ->Fill(part.track.getSigmaZ2(), part.track.getSigmaY2()); + hCorYSPhi->Fill(part.track.getSigmaSnp2(), part.track.getSigmaY2()); + hCorYTgl->Fill(part.track.getSigmaTgl2(), part.track.getSigmaY2()); + hCorYQoPt->Fill(part.track.getSigma1Pt2(), part.track.getSigmaY2()); + + hCorZSPhi->Fill(part.track.getSigmaSnp2(), part.track.getSigmaZ2()); + hCorZTgl->Fill(part.track.getSigmaTgl2(), part.track.getSigmaZ2()); + hCorZQoPt->Fill(part.track.getSigma1Pt2(), part.track.getSigmaZ2()); + + hCorSPhiTgl->Fill(part.track.getSigmaTgl2(), part.track.getSigmaSnp2()); + hCorSPhiQoPt->Fill(part.track.getSigma1Pt2(), part.track.getSigmaSnp2()); + + hCorTglQoPt->Fill(part.track.getSigma1Pt2(), part.track.getSigmaTgl2()); + + hMahDist->Fill(calcMahalanobisDist(part.track, mcTrack)); + } + } + + // normalise, set axis, fit and draw + auto doPullCalc = [](TH1F* h) { + h->Scale(1. / h->Integral("width")); + h->GetYaxis()->SetRangeUser(1e-5, 1.); + gPad->SetLogy(); + h->Draw("hist"); + h->Fit("gaus", "QMR", "", -3, 3); + if (auto f = h->GetFunction("gaus")) { + f->SetLineColor(kRed); + f->SetLineWidth(2); + f->Draw("same"); + const double mean = f->GetParameter(1); + const double sigma = f->GetParameter(2); + TLatex lat; + lat.SetNDC(); + lat.SetTextFont(42); + lat.SetTextSize(0.04); + lat.DrawLatex(0.62, 0.85, Form("#mu = %.4f", mean)); + lat.DrawLatex(0.62, 0.79, Form("#sigma = %.4f", sigma)); + } + }; + hMahDist->Scale(1. / hMahDist->Integral("width")); + TFitResultPtr fitres = hMahDist->Fit(fchi, "RMQS"); + + auto c = new TCanvas("cPull", "", 2000, 1000); + c->Divide(5, 5); + c->cd(1); + doPullCalc(hYPull); + c->cd(2); + hCorYZ->Draw("colz"); + c->cd(3); + hCorYSPhi->Draw("colz"); + c->cd(4); + hCorYTgl->Draw("colz"); + c->cd(5); + hCorYQoPt->Draw("colz"); + + c->cd(7); + doPullCalc(hZPull); + c->cd(8); + hCorZSPhi->Draw("colz"); + c->cd(9); + hCorZTgl->Draw("colz"); + c->cd(10); + hCorZQoPt->Draw("colz"); + + c->cd(13); + doPullCalc(hSPhiPull); + c->cd(14); + hCorSPhiTgl->Draw("colz"); + c->cd(15); + hCorSPhiQoPt->Draw("colz"); + + c->cd(19); + doPullCalc(hTglPull); + c->cd(20); + hCorTglQoPt->Draw("colz"); + + c->cd(); + const double xlow = 0.0; + const double xup = 0.4; + const double ylow = 0.0; + const double yup = 0.4; + auto pMahBig = new TPad("pMahBig", "Mahalanobis Distance", xlow, ylow, xup, yup); + pMahBig->SetFillStyle(4000); + pMahBig->SetBorderMode(0); + pMahBig->SetLeftMargin(0.12); + pMahBig->SetRightMargin(0.02); + pMahBig->SetBottomMargin(0.12); + pMahBig->SetTopMargin(0.05); + pMahBig->Draw(); + pMahBig->cd(); + hMahDist->Draw("hist"); + fchi->SetLineColor(kRed); + fchi->SetLineWidth(2); + fchi->Draw("same"); + const Double_t A_fit = fchi->GetParameter(0); + const Double_t k_fit = fchi->GetParameter(1); + const Double_t s_fit = fchi->GetParameter(2); + const Double_t A_err = fchi->GetParError(0); + const Double_t k_err = fchi->GetParError(1); + const Double_t s_err = fchi->GetParError(2); + const Double_t chi2 = fchi->GetChisquare(); + const Int_t ndf = fchi->GetNDF(); + TLatex lat; + lat.SetNDC(); + lat.SetTextFont(42); + lat.SetTextSize(0.038); + lat.SetTextAlign(11); + const Double_t xText = 0.55; + Double_t yText = 0.85; + const Double_t dy = 0.06; + lat.DrawLatex(xText, yText, Form("A = %.3g #pm %.3g", A_fit, A_err)); + yText -= dy; + lat.DrawLatex(xText, yText, Form("k (ndf) = %.3f #pm %.3f", k_fit, k_err)); + yText -= dy; + lat.DrawLatex(xText, yText, Form("scale s = %.3g #pm %.3g", s_fit, s_err)); + yText -= dy; + lat.DrawLatex(xText, yText, Form("#chi^{2}/ndf = %.2f / %d", chi2, ndf)); + yText -= dy; + if (fitres.Get()) { + lat.DrawLatex(xText, yText, Form("Fit status = %d", fitres->Status())); + yText -= dy; + } + + c->cd(25); + doPullCalc(hQoPtPull); + c->Draw(); + std::cout << " done\n"; + } + + if (createOutput) { + std::cout << "** Streaming output TTree to file ... " << std::flush; + TTree tree("ParticleInfo", "ParticleInfo"); + ParticleInfo pInfo; + tree.Branch("particle", &pInfo); + for (const auto& event : info) { + for (const auto& part : event) { + if (((part.clusters & 0x7f) != 0x7f) && !part.isPrimary) { + continue; + } + pInfo = part; + tree.Fill(); + } + } + tree.Write(); + file->Close(); } } diff --git a/Detectors/ITSMFT/ITS/macros/test/ITSMisaligner.C b/Detectors/ITSMFT/ITS/macros/test/ITSMisaligner.C index e04c2ca572804..eb6cb7a39b41c 100644 --- a/Detectors/ITSMFT/ITS/macros/test/ITSMisaligner.C +++ b/Detectors/ITSMFT/ITS/macros/test/ITSMisaligner.C @@ -78,7 +78,7 @@ void ITSMisaligner(const std::string& ccdbHost = "http://localhost:8080", long t std::string path = objectPath.empty() ? o2::base::DetectorNameConf::getAlignmentPath(detITS) : objectPath; LOGP(info, "Storing alignment object on {}/{}", ccdbHost, path); o2::ccdb::CcdbApi api; - map metadata; // can be empty + std::map 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); diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/CMakeLists.txt b/Detectors/ITSMFT/ITS/postprocessing/studies/CMakeLists.txt index 9794b69631d57..08ced25d0f5dc 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/CMakeLists.txt @@ -15,6 +15,7 @@ SOURCES src/ImpactParameter.cxx src/PIDStudy.cxx src/ITSStudiesConfigParam.cxx src/AnomalyStudy.cxx + src/ITSBeamBackgroundStudy.cxx src/TrackCheck.cxx src/TrackExtension.cxx src/Efficiency.cxx diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/ClusterizerSpec.h_notused.h b/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/ITSBeamBackgroundStudy.h similarity index 62% rename from Detectors/HMPID/workflow/include/HMPIDWorkflow/ClusterizerSpec.h_notused.h rename to Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/ITSBeamBackgroundStudy.h index 6102ec481c97c..cd96a9df8dee6 100644 --- a/Detectors/HMPID/workflow/include/HMPIDWorkflow/ClusterizerSpec.h_notused.h +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/ITSBeamBackgroundStudy.h @@ -9,19 +9,18 @@ // 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_ +#ifndef O2_ITS_BEAMBKG_STUDY_H +#define O2_ITS_BEAMBKG_STUDY_H #include "Framework/DataProcessorSpec.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" -namespace o2 -{ -namespace hmpid +namespace o2::its::study { -o2::framework::DataProcessorSpec getHMPIDClusterizerSpec(bool useMC); +using mask_t = o2::dataformats::GlobalTrackID::mask_t; -} // end namespace hmpid -} // end namespace o2 +o2::framework::DataProcessorSpec getITSBeamBackgroundStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC); -#endif /* STEER_DIGITIZERWORKFLOW_HMPIDCLUSTERIZERSPEC_H_ */ +} // namespace o2::its::study +#endif diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/Efficiency.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/Efficiency.cxx index bca1ec1e85001..494603641cde5 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/Efficiency.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/Efficiency.cxx @@ -593,7 +593,7 @@ int EfficiencyStudy::getDCAClusterTrackMC(int countDuplicated = 0) LOGP(info, "--------------- getDCAClusterTrackMC"); o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - o2::gpu::gpustd::array clusOriginalDCA, clusDuplicatedDCA; + std::array clusOriginalDCA, clusDuplicatedDCA; auto propagator = o2::base::Propagator::Instance(); auto bz = o2::base::Propagator::Instance()->getNominalBz(); @@ -833,7 +833,7 @@ void EfficiencyStudy::countDuplicatedAfterCuts() LOGP(info, "--------------- countDuplicatedAfterCuts"); o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - o2::gpu::gpustd::array clusOriginalDCA, clusDuplicatedDCA; + std::array clusOriginalDCA, clusDuplicatedDCA; auto propagator = o2::base::Propagator::Instance(); unsigned int rofIndexTrack = 0; @@ -1019,7 +1019,7 @@ void EfficiencyStudy::studyDCAcutsMC() // if not, keep it as a fake match -> increase the fake match counter // the efficiency of each one will be match counter / total of the duplicated clusters o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - o2::gpu::gpustd::array clusOriginalDCA, clusDuplicatedDCA; + std::array clusOriginalDCA, clusDuplicatedDCA; auto propagator = o2::base::Propagator::Instance(); unsigned int rofIndexTrack = 0; @@ -1346,7 +1346,7 @@ void EfficiencyStudy::studyClusterSelectionMC() } o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - o2::gpu::gpustd::array clusOriginalDCA, clusDuplicatedDCA; + std::array clusOriginalDCA, clusDuplicatedDCA; auto propagator = o2::base::Propagator::Instance(); unsigned int rofIndexTrack = 0; @@ -2176,7 +2176,7 @@ void EfficiencyStudy::getEfficiency(bool isMC) LOGP(info, "getEfficiency()"); o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - o2::gpu::gpustd::array clusOriginalDCA, clusDuplicatedDCA; + std::array clusOriginalDCA, clusDuplicatedDCA; auto propagator = o2::base::Propagator::Instance(); unsigned int rofIndexTrack = 0; @@ -2860,4 +2860,4 @@ DataProcessorSpec getEfficiencyStudy(mask_t srcTracksMask, mask_t srcClustersMas Options{}}; } -} // namespace o2::its::study \ No newline at end of file +} // namespace o2::its::study diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/Helpers.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/Helpers.cxx index 70b9bfb64dfd5..a5b3495047934 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/Helpers.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/Helpers.cxx @@ -10,6 +10,7 @@ // or submit itself to any jurisdiction. #include +#include // o2 includes #include "ITSStudies/Helpers.h" diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx new file mode 100644 index 0000000000000..fc9e139648672 --- /dev/null +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx @@ -0,0 +1,739 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ITSStudies/ITSBeamBackgroundStudy.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DetectorsBase/GRPGeomHelper.h" +#include "DataFormatsParameters/GRPObject.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" + +#include +#include +#include + +#include +#include + +#include "Framework/Task.h" +#include "Framework/Logger.h" + +// ZDC +#include "DataFormatsZDC/RecEventFlat.h" + +using namespace o2::framework; +using namespace o2::globaltracking; +using GTrackID = o2::dataformats::GlobalTrackID; + +namespace o2::its::study +{ +class ITSBeamBackgroundStudy : public Task +{ + public: + ITSBeamBackgroundStudy(std::shared_ptr dr, + std::shared_ptr gr, + bool isMC) : mDataRequest{dr}, mGGCCDBRequest(gr), mUseMC(isMC) {} + + void init(InitContext& ic) final; + void run(ProcessingContext&) final; + void endOfStream(EndOfStreamContext&) final; + void finaliseCCDB(ConcreteDataMatcher&, void*) final; + void save_and_reset(); + + // Custom + void process(o2::globaltracking::RecoContainer& recoData); + void updateTimeDependentParams(ProcessingContext& pc); + + private: + void getClusterPatterns(gsl::span&, gsl::span&, const o2::itsmft::TopologyDictionary&); + std::vector mPatterns; + + // ITS layout + int NStaves[7] = {12, 16, 20, 24, 30, 42, 48}; + int N_STAVES_IB = 48; + int N_CHIP_IB = 432; + + // Utilities + int ChipToLayer(int chip); + double ChipToPhi(int chip); + bool searchBCfromMap(std::map>& BCperorbit, long target_orbit, int target_bc); + + std::shared_ptr mGGCCDBRequest; + std::shared_ptr mDataRequest; + bool mUseMC; + const o2::itsmft::TopologyDictionary* mDict = nullptr; + + int mTFn = 0; + int mTF_first_after_dump = 1; + + int mStrobeFallBack = 594; + int mStrobe = mStrobeFallBack; + + // TODO: the following should be make configurable + + std::pair TimeWindowZDC = std::make_pair(5., 11.); + std::pair TimeWindowZNAr = std::make_pair(5.64507, 9.64507); + std::pair TimeWindowZNCr = std::make_pair(4.21299, 8.21299); + std::pair TimeWindowZNAl = std::make_pair(-11.3549, -8.35493); + std::pair TimeWindowZNCl = std::make_pair(-12.787, -9.78701); + + int targetClusterMinCol = 128; // definition of anomalous cluster + int targetClusterMaxRow = 29; // definition of anomalous cluster + + int mDumpEveryTF = 10; // use -1 to save only at the end + int mSkimmedOnlyAfterTF = 15000; + std::string mOutputChip = "chipevents"; + std::string mOutoutChipSkim = "chipeventstarget"; + + TH1F* TimeWindowCut; + TH1F* ZNACall; + TH1F* ZNCCall; + TH1F* ZDCAtagBC; + TH1F* ZDCCtagBC; + TH1I* Counters; + TTree* ITSChipEvtTree; + TTree* ITSChipEvtTargetTree; + + // Tree variables + int Tbc; + long Torbit; + int Tchip; + double Tphi; + int TZDCtag; + int Tnhit, Tnclus, Tnhit_no1pix, Tnclus_no1pix; + int Tnclus_s20, Tnclus_s100, Tnclus_s150; + int Tnclus_c20, Tnclus_c100, Tnclus_c128; + int Tnclus_target; + double Tnhit1, Tnhit10; + int Tmissingafter, Tmissingafter2; + int Tmincol, Tmaxcol; +}; + +void ITSBeamBackgroundStudy::updateTimeDependentParams(ProcessingContext& pc) +{ + // o2::base::GRPGeomHelper::instance().checkUpdates(pc); + // static bool initOnceDone = false; + // if (!initOnceDone) { // this param need to be queried only once + // initOnceDone = true; + // // mGeom = o2::its::GeometryTGeo::Instance(); + // // mGeom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot, o2::math_utils::TransformType::T2G)); + // } +} + +void ITSBeamBackgroundStudy::init(InitContext& ic) +{ + LOGP(info, "Initializing ITSBeamBackgroundStudy"); + LOGP(info, "Fetching ClusterDictionary"); + auto& mgr = o2::ccdb::BasicCCDBManager::instance(); + mgr.setURL("http://alice-ccdb.cern.ch"); + mgr.setTimestamp(o2::ccdb::getCurrentTimestamp()); + mDict = mgr.get("ITS/Calib/ClusterDictionary"); + + LOGP(info, "Setting up trees and histograms. They will be dumped on file every {} TFs", mDumpEveryTF); + + TimeWindowCut = new TH1F("ZDC bkg region", "ZNAr, ZNCr, -ZNAl, -ZNCl", 8, 0, 8); + TimeWindowCut->SetBinContent(1, TimeWindowZNAr.first); + TimeWindowCut->SetBinContent(2, TimeWindowZNAr.second); + TimeWindowCut->SetBinContent(3, TimeWindowZNCr.first); + TimeWindowCut->SetBinContent(4, TimeWindowZNCr.second); + TimeWindowCut->SetBinContent(5, -TimeWindowZNAl.first); + TimeWindowCut->SetBinContent(6, -TimeWindowZNAl.second); + TimeWindowCut->SetBinContent(7, -TimeWindowZNCl.first); + TimeWindowCut->SetBinContent(8, -TimeWindowZNCl.second); + ZNACall = new TH1F("ZNACall", "ZNACall", 40, -20, 20); + ZNCCall = new TH1F("ZNCCall", "ZNCCall", 40, -20, 20); + ZDCAtagBC = new TH1F("ZDCA tagged BC", "ZDCA tagged bc", 3564, 0, 3564); + ZDCCtagBC = new TH1F("ZDCC tagged BC", "ZDCC tagged bc", 3564, 0, 3564); + + Counters = new TH1I("Counters", "Counters", 20, 1, 21); + Counters->GetXaxis()->SetBinLabel(1, "TF"); + Counters->GetXaxis()->SetBinLabel(2, "ROF"); + Counters->GetXaxis()->SetBinLabel(3, "ZDCA evt"); + Counters->GetXaxis()->SetBinLabel(4, "ROF-ZDCA tagged"); + Counters->GetXaxis()->SetBinLabel(5, "ITStag any"); + Counters->GetXaxis()->SetBinLabel(6, "ITStag TO"); + Counters->GetXaxis()->SetBinLabel(7, "ITStag any + ZDC"); + Counters->GetXaxis()->SetBinLabel(8, "ITStag TO + ZDC"); + Counters->GetXaxis()->SetBinLabel(9, "ZDCC evt"); + Counters->GetXaxis()->SetBinLabel(10, "ROF-ZDCC tagged"); + + ITSChipEvtTree = new TTree("chipevt", "chipevt"); + + // Chip event branches + ITSChipEvtTree->Branch("TFprogress", &mTFn, "TFprogress/I"); + ITSChipEvtTree->Branch("orbit", &Torbit, "orbit/L"); + ITSChipEvtTree->Branch("bc", &Tbc, "bc/I"); + ITSChipEvtTree->Branch("chip", &Tchip, "chip/I"); + ITSChipEvtTree->Branch("phi", &Tphi, "phi/D"); + ITSChipEvtTree->Branch("zdctag", &TZDCtag, "zdctag/I"); + ITSChipEvtTree->Branch("nhit", &Tnhit, "nhit/I"); + ITSChipEvtTree->Branch("nhit_no1pix", &Tnhit_no1pix, "nhit_no1pix/I"); + ITSChipEvtTree->Branch("size1", &Tnhit1, "size1/D"); + ITSChipEvtTree->Branch("size10", &Tnhit10, "size10/D"); + ITSChipEvtTree->Branch("nclus", &Tnclus, "nclus/I"); + ITSChipEvtTree->Branch("nclus_no1pix", &Tnclus_no1pix, "nclus_no1pix/I"); + ITSChipEvtTree->Branch("nclus_target", &Tnclus_target, "nclus_target/I"); + ITSChipEvtTree->Branch("missingafter", &Tmissingafter, "missingafter/I"); + ITSChipEvtTree->Branch("missingafter2", &Tmissingafter2, "missingafter2/I"); + ITSChipEvtTree->Branch("mincol", &Tmincol, "mincol/I"); + ITSChipEvtTree->Branch("maxcol", &Tmaxcol, "maxcol/I"); + + ITSChipEvtTargetTree = ITSChipEvtTree->CloneTree(0); + ITSChipEvtTargetTree->SetName("chipevttarget"); + ITSChipEvtTargetTree->SetTitle("chipevttarget"); +} + +void ITSBeamBackgroundStudy::save_and_reset() +{ + + std::string outfile11 = mOutoutChipSkim + "_" + std::to_string(mTF_first_after_dump) + "_" + std::to_string(mTFn) + ".root"; + LOGP(info, "Writing ROOT file {}", outfile11); + TFile* F11 = TFile::Open(outfile11.c_str(), "recreate"); + TimeWindowCut->Write(); + ZNACall->Write(); + ZNCCall->Write(); + ZDCAtagBC->Write(); + ZDCCtagBC->Write(); + Counters->Write(); + ITSChipEvtTargetTree->Write(); + F11->Close(); + delete F11; + + if (mTFn <= mSkimmedOnlyAfterTF) { + std::string outfile1 = mOutputChip + "_" + std::to_string(mTF_first_after_dump) + "_" + std::to_string(mTFn) + ".root"; + LOGP(info, "Writing ROOT file {}", outfile1); + TFile* F1 = TFile::Open(outfile1.c_str(), "recreate"); + TimeWindowCut->Write(); + ZNACall->Write(); + ZNCCall->Write(); + ZDCAtagBC->Write(); + ZDCCtagBC->Write(); + Counters->Write(); + ITSChipEvtTree->Write(); // chip events and the skimmed one + ITSChipEvtTargetTree->Write(); + F1->Close(); + delete F1; + } + + LOGP(info, "Resetting historgrams and trees"); + // Delete clears data but keep the branch setup intact + ITSChipEvtTree->Reset(); // Delete(""); + ITSChipEvtTargetTree->Reset(); // Delete(""); + ZNACall->Reset(); + ZNCCall->Reset(); + ZDCAtagBC->Reset(); + ZDCCtagBC->Reset(); + Counters->Reset(); + + mTF_first_after_dump = mTFn + 1; +} + +void ITSBeamBackgroundStudy::endOfStream(EndOfStreamContext&) +{ + LOGP(info, "End of stream for ITSBeamBackgroundStudy"); + + save_and_reset(); + + delete TimeWindowCut; + delete ZNACall; + delete ZNCCall; + delete ZDCAtagBC; + delete ZDCCtagBC; + delete Counters; + delete ITSChipEvtTree; + delete ITSChipEvtTargetTree; +} + +void ITSBeamBackgroundStudy::run(ProcessingContext& pc) +{ + + if (mTFn == std::numeric_limits::max()) { + LOGP(error, "Max {} TFs exceeded. Skipping all next events", mTFn); + return; + } + + mTFn++; + + if (mDumpEveryTF > 0 && mTFn > 0 && (mTFn % mDumpEveryTF) == 0) { + LOGP(info, "Reached TF #{}. Exporting new root files", mTFn); + save_and_reset(); + } + + o2::globaltracking::RecoContainer recoData; + recoData.collectData(pc, *mDataRequest.get()); + // updateTimeDependentParams(pc); + LOGP(info, "Calling process() for TF: {}", mTFn); + process(recoData); +} + +void ITSBeamBackgroundStudy::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) +{ + return; +} + +// Custom area +void ITSBeamBackgroundStudy::process(o2::globaltracking::RecoContainer& recoData) +{ + + LOGP(info, "Processing RecoContainer"); + Counters->Fill(1); + + LOGP(info, "Retrieving ZDC data"); + auto RecBC = recoData.getZDCBCRecData(); + auto Energy = recoData.getZDCEnergy(); + auto TDCData = recoData.getZDCTDCData(); + auto Info2 = recoData.getZDCInfo(); + LOGP(info, "sizeof ZDC RC: {}, {}, {}, {}", RecBC.size(), Energy.size(), TDCData.size(), Info2.size()); + + LOGP(info, "Retrieving ITS clusters"); + auto rofRecVec = recoData.getITSClustersROFRecords(); + auto clusArr = recoData.getITSClusters(); + auto clusPatt = recoData.getITSClustersPatterns(); + LOGP(info, "sizeof ITS RC: {}, {}, {}", clusArr.size(), clusPatt.size(), rofRecVec.size()); + + // TODO: improve this + if (rofRecVec.size() == 576 || rofRecVec.size() == 192) { + mStrobe = 3564 / (rofRecVec.size() / 32); + LOGP(info, "Assuimg TF length = 32 orbits and setting strobe length to {} bc", mStrobe); + } else { + mStrobe = mStrobeFallBack; + LOGP(warning, "Unforeseen number of ROFs in the loop. Using the strobe length fall back value {}", mStrobe); + } + + std::map> ZNArtag{}; // ZDCAtag[orbit] = + std::map> ZNCrtag{}; + std::map> ZNAltag{}; + std::map> ZNCltag{}; + + // ________________________________________________________________ + // FILLING ZDC ARRAY + o2::zdc::RecEventFlat ev; + + ev.init(RecBC, Energy, TDCData, Info2); + + int bkgcounterAr = 0, bkgcounterCr = 0; + int bkgcounterAl = 0, bkgcounterCl = 0; + while (ev.next()) { + + int32_t itdcA = o2::zdc::TDCZNAC; // should be == 0 + int32_t itdcC = o2::zdc::TDCZNCC; + long zdcorbit = (long)ev.ir.orbit; + + // ZDC - A side + int nhitA = ev.NtdcV(itdcA); + for (int32_t ipos = 0; ipos < nhitA; ipos++) { + + double mytdc = o2::zdc::FTDCVal * ev.TDCVal[itdcA][ipos]; + + ZNACall->Fill(mytdc); + + if (mytdc >= TimeWindowZNAr.first && mytdc <= TimeWindowZNAr.second) { + + // Backgroud event found here! + bkgcounterAr++; + Counters->Fill(3); + ZDCAtagBC->Fill(ev.ir.bc); + + if (ZNArtag.find(zdcorbit) != ZNArtag.end()) { + bool double_count_bkg = ZNArtag[zdcorbit].insert((int)ev.ir.bc).second; + if (double_count_bkg) { + LOGP(warning, "Multiple ZDCAr counts in the same orbit/bc {}/{}", zdcorbit, ev.ir.bc); + } + } else { + std::set zdcbcs{(int)ev.ir.bc}; + ZNArtag[zdcorbit] = zdcbcs; + } + + } // and of ZNAr time window + + if (mytdc >= TimeWindowZNAl.first && mytdc <= TimeWindowZNAl.second) { + + // Backgroud event found here! + bkgcounterAl++; + Counters->Fill(3); + ZDCAtagBC->Fill(ev.ir.bc); + + if (ZNAltag.find(zdcorbit) != ZNAltag.end()) { + bool double_count_bkg = ZNAltag[zdcorbit].insert((int)ev.ir.bc).second; + if (double_count_bkg) { + LOGP(warning, "Multiple ZDCAl counts in the same orbit/bc {}/{}", zdcorbit, ev.ir.bc); + } + } else { + std::set zdcbcs{(int)ev.ir.bc}; + ZNAltag[zdcorbit] = zdcbcs; + } + + } // and of ZNAl time window + } + + // ZDC - C side + int nhitC = ev.NtdcV(itdcC); + for (int32_t ipos = 0; ipos < nhitC; ipos++) { + + double mytdc = o2::zdc::FTDCVal * ev.TDCVal[itdcC][ipos]; + + ZNCCall->Fill(mytdc); + + if (mytdc >= TimeWindowZNCr.first && mytdc <= TimeWindowZNCr.second) { + + // Backgroud event found here! + bkgcounterCr++; + Counters->Fill(9); + ZDCCtagBC->Fill(ev.ir.bc); + + if (ZNCrtag.find(zdcorbit) != ZNCrtag.end()) { + bool double_count_bkg = ZNCrtag[zdcorbit].insert((int)ev.ir.bc).second; + if (double_count_bkg) { + LOGP(warning, "Multiple ZNCr counts in the same orbit/bc {}/{}", zdcorbit, ev.ir.bc); + } + } else { + std::set zdcbcs{(int)ev.ir.bc}; + ZNCrtag[zdcorbit] = zdcbcs; + } + + } // end of ZNCr time window + + if (mytdc >= TimeWindowZNCl.first && mytdc <= TimeWindowZNCl.second) { + + // Backgroud event found here! + bkgcounterCl++; + Counters->Fill(9); + ZDCCtagBC->Fill(ev.ir.bc); + + if (ZNCltag.find(zdcorbit) != ZNCltag.end()) { + bool double_count_bkg = ZNCltag[zdcorbit].insert((int)ev.ir.bc).second; + if (double_count_bkg) { + LOGP(warning, "Multiple ZNCl counts in the same orbit/bc {}/{}", zdcorbit, ev.ir.bc); + } + } else { + std::set zdcbcs{(int)ev.ir.bc}; + ZNCltag[zdcorbit] = zdcbcs; + } + + } // end of ZNCl time window + } + } // end of while ev.next() + + LOGP(info, "Found background envents from ZNAright/left {}/{} -- from ZNCright/left {}/{}", bkgcounterAr, bkgcounterAl, bkgcounterCr, bkgcounterCl); + //__________________________________________________________________ + + getClusterPatterns(clusArr, clusPatt, *mDict); + + int inTFROFcounter = -1; + + std::vector ChipSeenInThisROF(N_CHIP_IB, false); // ChipSeenInThisROF[chipid] = true/false + std::vector ChipSeenInLastROF(N_CHIP_IB, false); // ChipSeenInLastROF[chipid] = true/false + std::vector ChipSeenInLast2ROF(N_CHIP_IB, false); // ChipSeenInLast2ROF[chipid] = true/false + + // Begin loop over ROFs + for (auto it = rofRecVec.rbegin(); it != rofRecVec.rend(); ++it) { + + auto& rofRec = *it; + + inTFROFcounter++; + + Counters->Fill(2); + + ChipSeenInLast2ROF = ChipSeenInLastROF; + ChipSeenInLastROF = ChipSeenInThisROF; + std::fill(ChipSeenInThisROF.begin(), ChipSeenInThisROF.end(), false); + + auto clustersInRof = rofRec.getROFData(clusArr); + auto patternsInRof = rofRec.getROFData(mPatterns); + + Tbc = (int)rofRec.getBCData().bc; + Torbit = (long)rofRec.getBCData().orbit; + + if (inTFROFcounter < 1) { + LOGP(info, "First of TF: ITS orbit/bc {}/{}", Torbit, Tbc); + } + + // shifting by 60 bc + int eff_bc = Tbc + 60; + long eff_orbit = Torbit; + if (eff_bc > 3563) { + eff_bc -= 3564; + eff_orbit += 1; + } + + // Making a bitmask with ZDC tags for this bc + bool isZNArtagged = searchBCfromMap(ZNArtag, (long)eff_orbit, eff_bc); + if (isZNArtagged) { + Counters->Fill(4); + } + + bool isZNAltagged = searchBCfromMap(ZNAltag, (long)eff_orbit, eff_bc); + if (isZNAltagged) { + Counters->Fill(4); + } + + bool isZNCrtagged = searchBCfromMap(ZNCrtag, (long)eff_orbit, eff_bc); + if (isZNCrtagged) { + Counters->Fill(10); + } + + bool isZNCltagged = searchBCfromMap(ZNCltag, (long)eff_orbit, eff_bc); + if (isZNCltagged) { + Counters->Fill(10); + } + + TZDCtag = 0; + TZDCtag |= (isZNArtagged << 0); + TZDCtag |= (isZNAltagged << 1); + TZDCtag |= (isZNCrtagged << 2); + TZDCtag |= (isZNCltagged << 3); + + if (TZDCtag > 0) { + LOGP(info, "ZDC tag with mask {}: ZNAright = {} - ZNAleft = {} - ZNCright = {} - ZNCleft = {}", + TZDCtag, (TZDCtag >> 0) & 1, (TZDCtag >> 1) & 1, (TZDCtag >> 2) & 1, (TZDCtag >> 3) & 1); + } + + // preparing arrays for clusters analysis + std::set AvailableChips{}; + std::map> MAPsize{}; // MAP[chip] = {list if sizes} + std::map> MAPcols{}; // MAP[chip] = {list of column span} + std::map MAPntarget{}; // MAP[chip] = number of bad clusters in chip + std::map MAPcoo_mincol{}; // MAP[chip] = minimum of column coordinate + std::map MAPcoo_maxcol{}; // MAP[chip] = maximum of (column coordinate + colspan) + + // Finally loop over clusters + int ntarget_in_rof = 0; + for (int iclus = 0; iclus < clustersInRof.size(); iclus++) { + + const auto& compClus = clustersInRof[iclus]; + + auto chipid = compClus.getSensorID(); + + // Analyze only IB + if (ChipToLayer(chipid) > 2) { + continue; + } + + ChipSeenInThisROF[chipid] = true; + + int coo_col = (int)compClus.getCol(); + int coo_row = (int)compClus.getRow(); + + auto patti = patternsInRof[iclus]; + int npix = patti.getNPixels(); + int colspan = patti.getColumnSpan(); + int rowspan = patti.getRowSpan(); + + bool newchip = AvailableChips.insert(chipid).second; + if (newchip) { + MAPsize[chipid] = std::vector{}; + MAPcols[chipid] = std::vector{}; + MAPntarget[chipid] = 0; + MAPcoo_mincol[chipid] = coo_col; + MAPcoo_maxcol[chipid] = coo_col + colspan; + } + + MAPsize[chipid].push_back(npix); + MAPcols[chipid].push_back(colspan); + if (colspan >= targetClusterMinCol && rowspan <= targetClusterMaxRow) { + // Anomalous cluster found + MAPntarget[chipid] += 1; + ntarget_in_rof++; + } + MAPcoo_mincol[chipid] = TMath::Min(MAPcoo_mincol[chipid], coo_col); + MAPcoo_maxcol[chipid] = TMath::Max(MAPcoo_maxcol[chipid], coo_col + colspan); + + } // end of loop over clusters in rof + + if (ntarget_in_rof == 0 && mTFn > mSkimmedOnlyAfterTF + 2) { // extra 2 to avoid edge effects? + // do not need extra computations for this rof since it will not be saved in any case + continue; + } + + for (int ic : AvailableChips) { + + Tchip = ic; + + if (inTFROFcounter < 1) { + Tmissingafter = -1; + } else if (ChipSeenInLastROF[ic]) { + Tmissingafter = 0; + } else { + Tmissingafter = 1; + } + + if (inTFROFcounter < 2) { + Tmissingafter2 = -1; + } else if (ChipSeenInLast2ROF[ic]) { + Tmissingafter2 = 0; + } else { + Tmissingafter2 = 1; + } + + Tphi = ChipToPhi(ic); + + Tnclus = MAPsize[ic].size(); + Tmincol = MAPcoo_mincol[ic]; + Tmaxcol = MAPcoo_maxcol[ic]; + + std::sort(MAPsize[ic].begin(), MAPsize[ic].end(), std::greater<>()); + + Tnhit = Tnclus_s20 = Tnclus_s100 = Tnclus_s150 = 0; + Tnhit1 = Tnhit10 = 0.; + Tnclus_c20 = Tnclus_c100 = Tnclus_c128 = 0; + Tnclus_target = MAPntarget[ic]; + Tnhit_no1pix = 0; + Tnclus_no1pix = 0; + + int nhit_no1pix = 0; + int nclus10 = 0, nclus1 = 0; + + for (int nh : MAPsize[ic]) { + + Tnhit += nh; + + if (nh > 1) { + Tnhit_no1pix += nh; + Tnclus_no1pix += 1; + } + + if (nclus10 < 10) { + nclus10++; + Tnhit10 += 1. * nh; + } + + if (nclus1 < 1) { + nclus1++; + Tnhit1 += 1. * nh; + } + + Tnclus_s20 += (nh >= 20); + Tnclus_s100 += (nh >= 100); + Tnclus_s150 += (nh >= 150); + } + + Tnhit10 = (nclus10 == 0) ? 0. : 1. * Tnhit10 / nclus10; + + for (int nc : MAPcols[ic]) { + Tnclus_c20 += (nc >= 20); + Tnclus_c100 += (nc >= 100); + Tnclus_c128 += (nc >= 128); + } + + ITSChipEvtTree->Fill(); + if (Tnclus_target > 0) { + ITSChipEvtTargetTree->Fill(); + } + + } // end of loop over available chips + } // end of loop over ROFs +} + +// TODO: To be improved using geometry tools +int ITSBeamBackgroundStudy::ChipToLayer(int chip) +{ + if (chip < 108) { + return 0; + } + if (chip < 252) { + return 1; + } + if (chip < 432) { + return 2; + } + if (chip < 3120) { + return 3; + } + if (chip < 6480) { + return 4; + } + if (chip < 14712) { + return 5; + } + return 6; +} + +// TODO: To be improved using geometry tools +double ITSBeamBackgroundStudy::ChipToPhi(int chip) +{ + int staveinlayer = (int)(chip / 9); + for (int il = 0; il < ChipToLayer(chip); il++) { + staveinlayer -= NStaves[il]; + } + return 2. * TMath::Pi() * (0.5 + staveinlayer) / NStaves[ChipToLayer(chip)]; +} + +bool ITSBeamBackgroundStudy::searchBCfromMap(std::map>& BCperorbit, long its_orbit, int its_bc) +{ + auto it = BCperorbit.find(its_orbit); + if (it == BCperorbit.end()) { + return false; + } + + for (auto bc : it->second) { + if ((bc / mStrobe) == (its_bc / mStrobe)) { + return true; + } + } + return false; +} + +void ITSBeamBackgroundStudy::getClusterPatterns(gsl::span& ITSclus, gsl::span& ITSpatt, const o2::itsmft::TopologyDictionary& mdict) +{ + mPatterns.clear(); + mPatterns.reserve(ITSclus.size()); + auto pattIt = ITSpatt.begin(); + + for (unsigned int iClus{0}; iClus < ITSclus.size(); ++iClus) { + auto& clus = ITSclus[iClus]; + + auto pattID = clus.getPatternID(); + o2::itsmft::ClusterPattern patt; + + if (pattID == o2::itsmft::CompCluster::InvalidPatternID || mdict.isGroup(pattID)) { + patt.acquirePattern(pattIt); + } else { + patt = mdict.getPattern(pattID); + } + + mPatterns.push_back(patt); + } +} + +// getter +DataProcessorSpec getITSBeamBackgroundStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC) +{ + + // std::cout<<"DEBBUG track and clus masks "< outputs; + auto dataRequest = std::make_shared(); + dataRequest->requestClusters(srcClustersMask, useMC); + // dataRequest->requestTracks(GTrackID::getSourcesMask("ZDC"), useMC); + + dataRequest->requestTracks(srcTracksMask, useMC); + + auto ggRequest = std::make_shared(false, // orbitResetTime + true, // GRPECS=true + false, // GRPLHCIF + false, // GRPMagField + false, // askMatLUT + o2::base::GRPGeomRequest::Aligned, // geometry + dataRequest->inputs, + true); + return DataProcessorSpec{ + "its-beambkg-study", + dataRequest->inputs, + outputs, + AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, useMC)}, + Options{}}; +} + +} // namespace o2::its::study diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/ImpactParameter.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ImpactParameter.cxx index 5ca1bf2bd5c8f..bc8b931190ed1 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/ImpactParameter.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ImpactParameter.cxx @@ -29,7 +29,7 @@ #include "CommonUtils/TreeStreamRedirector.h" #include "DetectorsBase/GRPGeomHelper.h" #include "DataFormatsParameters/GRPECSObject.h" -#include "ITSMFTBase/DPLAlpideParam.h" +#include "DataFormatsITSMFT/DPLAlpideParam.h" #include "DetectorsCommonDataFormats/DetID.h" #include "Framework/DeviceSpec.h" #include "CommonUtils/ConfigurableParam.h" @@ -358,7 +358,7 @@ void ImpactParameterStudy::process(o2::globaltracking::RecoContainer& recoData) auto trueID = trueVec_globID_contr[it]; const o2::track::TrackParCov& trc = recoData.getTrackParam(trueID); auto pt = trc.getPt(); - o2::gpu::gpustd::array dcaInfo{-999., -999.}; + std::array dcaInfo{-999., -999.}; // LOGP(info, " ---> Bz={}", o2::base::Propagator::Instance()->getNominalBz()); o2::track::TrackPar trcTmp{trc}; if (o2::base::Propagator::Instance()->propagateToDCABxByBz({Pvtx_refitted.getX(), Pvtx_refitted.getY(), Pvtx_refitted.getZ()}, trcTmp, 2.f, matCorr, &dcaInfo)) { diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/PIDStudy.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/PIDStudy.cxx index 4b0f553eb774b..9a7f6c218cd12 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/PIDStudy.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/PIDStudy.cxx @@ -91,7 +91,7 @@ class PIDStudy : public Task std::shared_ptr gr, bool isMC, std::shared_ptr kineReader) : mDataRequest{dr}, mGGCCDBRequest(gr), mUseMC(isMC), mKineReader(kineReader){}; - ~PIDStudy() final = default; + ~PIDStudy() override = default; void init(InitContext& ic) final; void run(ProcessingContext&) final; void endOfStream(EndOfStreamContext&) final; diff --git a/Detectors/ITSMFT/ITS/postprocessing/workflow/standalone-postprocessing-workflow.cxx b/Detectors/ITSMFT/ITS/postprocessing/workflow/standalone-postprocessing-workflow.cxx index 30fb39c77f235..405e80475bd25 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/workflow/standalone-postprocessing-workflow.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/workflow/standalone-postprocessing-workflow.cxx @@ -16,12 +16,14 @@ #include "Framework/CompletionPolicyHelpers.h" #include "GlobalTrackingWorkflowHelpers/InputHelper.h" #include "DetectorsRaw/HBFUtilsInitializer.h" +#include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" // Include studies hereafter #include "ITSStudies/ImpactParameter.h" #include "ITSStudies/AvgClusSize.h" #include "ITSStudies/PIDStudy.h" #include "ITSStudies/AnomalyStudy.h" +#include "ITSStudies/ITSBeamBackgroundStudy.h" #include "ITSStudies/Efficiency.h" #include "ITSStudies/TrackCheck.h" #include "ITSStudies/TrackExtension.h" @@ -42,7 +44,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ {"input-from-upstream", VariantType::Bool, false, {"read clusters from the clusterer"}}, - {"track-sources", VariantType::String, std::string{"ITS,ITS-TPC-TRD-TOF,ITS-TPC-TOF,ITS-TPC,ITS-TPC-TRD"}, {"comma-separated list of track sources to use"}}, + {"track-sources", VariantType::String, std::string{"ITS,ITS-TPC-TRD-TOF,ITS-TPC-TOF,ITS-TPC,ITS-TPC-TRD,ZDC"}, {"comma-separated list of track sources to use"}}, {"cluster-sources", VariantType::String, std::string{"ITS"}, {"comma-separated list of cluster sources to use"}}, {"disable-root-input", VariantType::Bool, false, {"disable root-files input reader"}}, {"disable-mc", VariantType::Bool, false, {"disable MC propagation even if available"}}, @@ -51,9 +53,11 @@ void customize(std::vector& workflowOptions) {"track-study", VariantType::Bool, false, {"Perform the track study"}}, {"impact-parameter-study", VariantType::Bool, false, {"Perform the impact parameter study"}}, {"anomaly-study", VariantType::Bool, false, {"Perform the anomaly study"}}, + {"its-beambkg-study", VariantType::Bool, false, {"Perform the ITS beam background study"}}, {"track-extension-study", VariantType::Bool, false, {"Perform the track extension study"}}, {"efficiency-study", VariantType::Bool, false, {"Perform the efficiency study"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + o2::itsmft::DPLAlpideParamInitializer::addITSConfigOption(options); // o2::raw::HBFUtilsInitializer::addConfigOption(options, "o2_tfidinfo.root"); std::swap(workflowOptions, options); } @@ -112,6 +116,17 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) } specs.emplace_back(o2::its::study::getAnomalyStudy(srcCls, useMC)); } + if (configcontext.options().get("its-beambkg-study")) { + anyStudy = true; + + srcCls = GID::getSourcesMask(configcontext.options().get("cluster-sources")); + srcTrc = GID::getSourcesMask(configcontext.options().get("track-sources")); + + if (!configcontext.options().get("input-from-upstream")) { + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcCls, srcTrc, srcTrc, useMC, srcCls, srcTrc); + } + specs.emplace_back(o2::its::study::getITSBeamBackgroundStudy(srcTrc, srcCls, useMC)); + } if (configcontext.options().get("track-extension-study")) { if (!useMC) { LOGP(fatal, "Track Extension Study needs MC!"); @@ -135,8 +150,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) LOGP(info, "No study selected, dryrunning"); } - o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); - // write the configuration used for the studies workflow + // o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + // write the configuration used for the studies workflow o2::conf::ConfigurableParam::writeINI("o2_its_standalone_configuration.ini"); return std::move(specs); diff --git a/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt b/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt index 3e1544c65b9de..be42015b95795 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt @@ -10,12 +10,7 @@ # or submit itself to any jurisdiction. o2_add_library(ITSReconstruction - SOURCES src/ClustererTask.cxx - src/CookedTracker.cxx - src/CookedConfigParam.cxx - src/RecoGeomHelper.cxx - src/FastMultEstConfig.cxx - src/FastMultEst.cxx + SOURCES src/RecoGeomHelper.cxx PUBLIC_LINK_LIBRARIES O2::ITSBase O2::ITSMFTReconstruction O2::DataFormatsITS @@ -23,10 +18,4 @@ o2_add_library(ITSReconstruction o2_target_root_dictionary( ITSReconstruction - HEADERS include/ITSReconstruction/ClustererTask.h - include/ITSReconstruction/CookedTracker.h - include/ITSReconstruction/CookedConfigParam.h - include/ITSReconstruction/RecoGeomHelper.h - include/ITSReconstruction/FastMultEst.h - include/ITSReconstruction/FastMultEstConfig.h - LINKDEF src/CookedTrackerLinkDef.h) + HEADERS include/ITSReconstruction/RecoGeomHelper.h) diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/ClustererTask.h b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/ClustererTask.h deleted file mode 100644 index 16ac9dd63c631..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/ClustererTask.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ClustererTask.h -/// \brief Definition of the ITS cluster finder task - -#ifndef ALICEO2_ITS_CLUSTERERTASK -#define ALICEO2_ITS_CLUSTERERTASK - -#include "ITSMFTReconstruction/ChipMappingITS.h" -#include "ITSMFTReconstruction/PixelReader.h" -#include "ITSMFTReconstruction/RawPixelReader.h" -#include "ITSMFTReconstruction/DigitPixelReader.h" -#include "ITSMFTReconstruction/Clusterer.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include -#include - -namespace o2 -{ -class MCCompLabel; -namespace dataformats -{ -template -class MCTruthContainer; -} - -namespace its -{ - -class ClustererTask -{ - using Clusterer = o2::itsmft::Clusterer; - using CompCluster = o2::itsmft::CompCluster; - using CompClusterExt = o2::itsmft::CompClusterExt; - using MCTruth = o2::dataformats::MCTruthContainer; - - 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 writeTree(std::string basename, int i); - void setMaxROframe(int max) { maxROframe = max; } - int getMaxROframe() const { return maxROframe; } - - private: - int maxROframe = std::numeric_limits::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 mReaderMC; ///< reader for MC data - std::unique_ptr> mReaderRaw; ///< reader for raw data - - Clusterer mClusterer; ///< Cluster finder - - std::vector mCompClus; //!< vector of compact clusters - - std::vector mROFRecVec; //!< vector of ROFRecord references - - MCTruth mClsLabels; //! MC labels - - std::vector mPatterns; - - ClassDefNV(ClustererTask, 2); -}; -} // namespace its -} // namespace o2 - -#endif /* ALICEO2_ITS_CLUSTERERTASK */ diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedConfigParam.h b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedConfigParam.h deleted file mode 100644 index bfc111d0a3803..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedConfigParam.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef ALICEO2_COOKEDTRACKINGPARAM_H_ -#define ALICEO2_COOKEDTRACKINGPARAM_H_ - -#include "CommonUtils/ConfigurableParamHelper.h" - -namespace o2 -{ -namespace its -{ - -struct CookedConfigParam : public o2::conf::ConfigurableParamHelper { - // seed "windows" in z and phi: makeSeeds - float zWin = 0.33; - float minPt = 0.05; - // Maximal accepted impact parameters for the seeds - float maxDCAxy = 3.; - float maxDCAz = 3.; - // Space-point resolution - float sigma = 0.0005; - // Tracking "road" from layer to layer - float roadY = 0.2; - float roadZ = 0.3; - // Minimal number of attached clusters - int minNumberOfClusters = 4; - - O2ParamDef(CookedConfigParam, "ITSCookedTracker"); -}; - -} // namespace its -} // namespace o2 -#endif diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedTracker.h b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedTracker.h deleted file mode 100644 index 918f7f82cbff8..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedTracker.h +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file CookedTracker.h -/// \brief Definition of the "Cooked Matrix" ITS tracker -/// \author iouri.belikov@cern.ch - -#ifndef ALICEO2_ITS_COOKEDTRACKER_H -#define ALICEO2_ITS_COOKEDTRACKER_H - -//------------------------------------------------------------------------- -// A stand-alone ITS tracker -// The pattern recongintion based on the "cooked covariance" approach -//------------------------------------------------------------------------- - -#include -#include -#include "ITSBase/GeometryTGeo.h" -#include "MathUtils/Cartesian.h" -#include "DataFormatsITSMFT/Cluster.h" -#include "DataFormatsITS/TrackITS.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "ReconstructionDataFormats/Vertex.h" -#include "ITSReconstruction/CookedConfigParam.h" - -using Point3Df = o2::math_utils::Point3D; - -namespace o2 -{ -class MCCompLabel; -namespace dataformats -{ -template -class MCTruthContainer; -} -namespace itsmft -{ -class TopologyDictionary; -class CompClusterExt; -} // namespace itsmft -namespace its -{ -class CookedTracker -{ - using Cluster = o2::itsmft::Cluster; - using CompClusterExt = o2::itsmft::CompClusterExt; - using Vertex = o2::dataformats::Vertex>; - - public: - CookedTracker(Int_t nThreads = 1); - CookedTracker(const CookedTracker&) = delete; - CookedTracker& operator=(const CookedTracker& tr) = delete; - ~CookedTracker() = default; - - void setConfigParams() - { - const auto& par = CookedConfigParam::Instance(); - LOG(info) << " Setting configurable parameters..."; - - gzWin = par.zWin; - gminPt = par.minPt; - gmaxDCAxy = par.maxDCAxy; - gmaxDCAz = par.maxDCAz; - gSigma2 = par.sigma * par.sigma; - gRoadY = par.roadY; - gRoadZ = par.roadZ; - gminNumberOfClusters = par.minNumberOfClusters; - } - void setParameters(const std::vector& par) - { - gzWin = par[0]; - gminPt = par[1]; - gmaxDCAxy = par[3]; - gmaxDCAz = par[4]; - gSeedingLayer1 = par[5]; - gSeedingLayer2 = par[6]; - gSeedingLayer3 = par[7]; - gSigma2 = par[8] * par[8]; - gmaxChi2PerCluster = par[9]; - gmaxChi2PerTrack = par[10]; - gRoadY = par[11]; - gRoadZ = par[12]; - gminNumberOfClusters = par[13]; - } - void setParametersCosmics() - { - // seed "windows" in z and phi: makeSeeds - gzWin = 84.; // length of the L3 - gminPt = 10.; - // Maximal accepted impact parameters for the seeds - gmaxDCAxy = 19.4; // radius of the L3 - gmaxDCAz = 42.; // half-lenght of the L3 - // Space point resolution - gSigma2 = 0.2 * 0.2; - // Tracking "road" from layer to layer - gRoadY = 1.5; // Chip size in Y - gRoadZ = 3.0; // Chip size in Z - } - - void setVertices(const std::vector& vertices) - { - mVertices = &vertices; - } - - Double_t getX() const { return mX; } - Double_t getY() const { return mY; } - Double_t getZ() const { return mZ; } - Double_t getSigmaX() const { return mSigmaX; } - Double_t getSigmaY() const { return mSigmaY; } - Double_t getSigmaZ() const { return mSigmaZ; } - o2::MCCompLabel cookLabel(TrackITSExt& t, Float_t wrong) const; - void setExternalIndices(TrackITSExt& t) const; - Double_t getBz() const; - void setBz(Double_t bz) { mBz = bz; } - - void setNumberOfThreads(Int_t n) { mNumOfThreads = n; } - Int_t getNumberOfThreads() const { return mNumOfThreads; } - - using TrackInserter = std::function; - // These functions must be implemented - template - void process(gsl::span clusters, gsl::span::iterator& it, const o2::itsmft::TopologyDictionary* dict, U& tracks, V& clusIdx, o2::itsmft::ROFRecord& rof) - { - TrackInserter inserter = [&tracks, &clusIdx, this](const TrackITSExt& t) -> int { - // convert internal track to output format - auto& trackNew = tracks.emplace_back(t); - int noc = t.getNumberOfClusters(); - int clEntry = clusIdx.size(); - 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(this->mFirstInFrame + idx); - } - trackNew.setClusterRefs(clEntry, noc); - trackNew.setPattern(0x7f); // this tracker finds only complete tracks - return tracks.size(); - }; - process(clusters, it, dict, inserter, rof); - } - void process(gsl::span const& clusters, gsl::span::iterator& it, const o2::itsmft::TopologyDictionary* dict, TrackInserter& inserter, o2::itsmft::ROFRecord& rof); - const Cluster* getCluster(Int_t index) const; - - void setGeometry(o2::its::GeometryTGeo* geom); - void setMCTruthContainers(const o2::dataformats::MCTruthContainer* clsLabels, std::vector* trkLabels) - { - mClsLabels = clsLabels; - mTrkLabels = trkLabels; - } - - void setContinuousMode(bool mode) { mContinuousMode = mode; } - bool getContinuousMode() { return mContinuousMode; } - - static void setMostProbablePt(float pt) { mMostProbablePt = pt; } - static auto getMostProbablePt() { return mMostProbablePt; } - - // internal helper classes - class ThreadData; - class Layer; - - protected: - static constexpr int kNLayers = 7; - int loadClusters(); - void unloadClusters(); - std::tuple processLoadedClusters(TrackInserter& inserter); - - std::vector trackInThread(Int_t first, Int_t last); - o2::its::TrackITSExt cookSeed(const Point3Df& r1, Point3Df& r2, const Point3Df& tr3, float rad2, float rad3, float_t alpha, float_t bz); - void makeSeeds(std::vector& seeds, Int_t first, Int_t last); - void trackSeeds(std::vector& seeds); - - Bool_t attachCluster(Int_t& volID, Int_t nl, Int_t ci, TrackITSExt& t, const TrackITSExt& o) const; - - void makeBackPropParam(std::vector& seeds) const; - bool makeBackPropParam(TrackITSExt& track) const; - - private: - /*** Tracking parameters ***/ - // seed "windows" in z and phi: makeSeeds - static Float_t gzWin; - static Float_t gminPt; - static Float_t mMostProbablePt; ///< settable most probable pt - // Maximal accepted impact parameters for the seeds - static Float_t gmaxDCAxy; - static Float_t gmaxDCAz; - // Layers for the seeding - static Int_t gSeedingLayer1; - static Int_t gSeedingLayer2; - static Int_t gSeedingLayer3; - // Space point resolution - static Float_t gSigma2; - // Max accepted chi2 - static Float_t gmaxChi2PerCluster; - static Float_t gmaxChi2PerTrack; - // Tracking "road" from layer to layer - static Float_t gRoadY; - static Float_t gRoadZ; - // Minimal number of attached clusters - static Int_t gminNumberOfClusters; - - bool mContinuousMode = true; ///< triggered or cont. mode - const o2::its::GeometryTGeo* mGeom = nullptr; /// interface to geometry - const o2::dataformats::MCTruthContainer* mClsLabels = nullptr; /// Cluster MC labels - std::vector* mTrkLabels = nullptr; /// Track MC labels - std::uint32_t mFirstInFrame = 0; ///< Index of the 1st cluster of a frame (within the loaded vector of clusters) - - Int_t mNumOfThreads; ///< Number of tracking threads - - Double_t mBz; ///< Effective Z-component of the magnetic field (kG) - - const std::vector* mVertices = nullptr; - Double_t mX = 0.; ///< X-coordinate of the primary vertex - Double_t mY = 0.; ///< Y-coordinate of the primary vertex - Double_t mZ = 0.; ///< Z-coordinate of the primary vertex - - Double_t mSigmaX = 2.; ///< error of the primary vertex position in X - Double_t mSigmaY = 2.; ///< error of the primary vertex position in Y - Double_t mSigmaZ = 2.; ///< error of the primary vertex position in Z - - static Layer sLayers[kNLayers]; ///< Layers filled with clusters - std::vector mSeeds; ///< Track seeds - - std::vector mClusterCache; - - ClassDefNV(CookedTracker, 1); -}; - -class CookedTracker::Layer -{ - public: - Layer(); - Layer(const Layer&) = delete; - Layer& operator=(const Layer& tr) = delete; - - void init(); - Bool_t insertCluster(const Cluster* c); - void setR(Double_t r) { mR = r; } - void unloadClusters(); - void selectClusters(std::vector& s, Float_t phi, Float_t dy, Float_t z, Float_t dz); - Int_t findClusterIndex(Float_t z) const; - Float_t getR() const { return mR; } - const Cluster* getCluster(Int_t i) const { return mClusters[i]; } - Float_t getAlphaRef(Int_t i) const { return mAlphaRef[i]; } - Float_t getClusterPhi(Int_t i) const { return mPhi[i]; } - Int_t getNumberOfClusters() const { return mClusters.size(); } - void setGeometry(o2::its::GeometryTGeo* geom) { mGeom = geom; } - - protected: - enum { kNSectors = 21 }; - - Float_t mR; ///< mean radius of this layer - const o2::its::GeometryTGeo* mGeom = nullptr; ///< interface to geometry - std::vector mClusters; ///< All clusters - std::vector mAlphaRef; ///< alpha of the reference plane - std::vector mPhi; ///< cluster phi - std::vector> mSectors[kNSectors]; ///< Cluster indices sector-by-sector -}; -} // namespace its -} // namespace o2 -#endif /* ALICEO2_ITS_COOKEDTRACKER_H */ diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/FastMultEst.h b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/FastMultEst.h deleted file mode 100644 index 9e8299e89b404..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/FastMultEst.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file FastMultEst.h -/// \brief Fast multiplicity estimator for ITS -/// \author ruben.shahoyan@cern.ch - -#ifndef ALICEO2_ITS_FASTMULTEST_ -#define ALICEO2_ITS_FASTMULTEST_ - -#include "ITSMFTReconstruction/ChipMappingITS.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include -#include "ITSReconstruction/FastMultEstConfig.h" -#include -#include - -namespace o2 -{ -namespace its -{ - -struct FastMultEst { - - static constexpr int NLayers = o2::itsmft::ChipMappingITS::NLayers; - - float mult = 0.; /// estimated signal clusters multipliciy at reference (1st?) layer - float noisePerChip = 0.; /// estimated or imposed noise per chip - float cov[3] = {0.}; /// covariance matrix of estimation - float chi2 = 0.; /// chi2 - int nLayersUsed = 0; /// number of layers actually used - uint32_t lastRandomSeed = 0; /// state of the gRandom before - - std::array nClPerLayer{0}; // measured N Cl per layer selectROFs - FastMultEst(); - - static uint32_t getCurrentRandomSeed(); - int selectROFs(const gsl::span rofs, const gsl::span clus, - const gsl::span trig, std::vector& sel); - - void fillNClPerLayer(const gsl::span& clusters); - float process(const std::array ncl) - { - return FastMultEstConfig::Instance().imposeNoisePerChip > 0 ? processNoiseImposed(ncl) : processNoiseFree(ncl); - } - float processNoiseFree(const std::array ncl); - float processNoiseImposed(const std::array ncl); - float process(const gsl::span& clusters) - { - fillNClPerLayer(clusters); - return process(nClPerLayer); - } - static bool sSeedSet; - - ClassDefNV(FastMultEst, 1); -}; - -} // namespace its -} // namespace o2 - -#endif diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/RecoGeomHelper.h b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/RecoGeomHelper.h index f9d3f1ae46752..a7d814f02d011 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/RecoGeomHelper.h +++ b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/RecoGeomHelper.h @@ -103,7 +103,7 @@ struct RecoGeomHelper { static constexpr float ladderWidth() { return o2::itsmft::SegmentationAlpide::SensorSizeRows; } static constexpr float ladderWidthInv() { return 1. / ladderWidth(); } - void init(); + void init(int minLayer = 0, int maxLayer = getNLayers()); void print() const; ClassDefNV(RecoGeomHelper, 0); diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/TrivialVertexer.h b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/TrivialVertexer.h deleted file mode 100644 index 3eb218dc973f6..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/TrivialVertexer.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file TrivialVertexer.h -/// \brief Definition of the ITS trivial vertex finder -#ifndef ALICEO2_ITS_TRIVIALVERTEXER_H -#define ALICEO2_ITS_TRIVIALVERTEXER_H - -#include - -#include "Rtypes.h" // for TrivialVertexer::Class, Double_t, ClassDef, etc - -class TFile; -class TTree; -class FairMCEventHeader; - -namespace o2 -{ -namespace itsmft -{ -class Cluster; -} -} // namespace o2 - -namespace o2 -{ -class MCCompLabel; -namespace dataformats -{ -template -class MCTruthContainer; -} -namespace its -{ -class TrivialVertexer -{ - using Cluster = o2::itsmft::Cluster; - using Label = o2::MCCompLabel; - - public: - TrivialVertexer(); - ~TrivialVertexer(); - - TrivialVertexer(const TrivialVertexer&) = delete; - TrivialVertexer& operator=(const TrivialVertexer&) = delete; - - Bool_t openInputFile(const Char_t*); - - void process(const std::vector& clusters, std::vector>& vertices); - void setMCTruthContainer(const o2::dataformats::MCTruthContainer* truth) { mClsLabels = truth; } - - private: - const o2::dataformats::MCTruthContainer* mClsLabels = nullptr; // Cluster MC labels - - TFile* mFile = nullptr; - TTree* mTree = nullptr; - FairMCEventHeader* mHeader = nullptr; -}; -} // namespace its -} // namespace o2 - -#endif /* ALICEO2_ITS_TRIVIALVERTEXER_H */ diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/ClustererTask.cxx b/Detectors/ITSMFT/ITS/reconstruction/src/ClustererTask.cxx deleted file mode 100644 index fb4e4ac7b6fa2..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/src/ClustererTask.cxx +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ClustererTask.cxx -/// \brief Implementation of the ITS cluster finder task - -#include "DetectorsCommonDataFormats/DetID.h" -#include "ITSReconstruction/ClustererTask.h" -#include "MathUtils/Cartesian.h" -#include "MathUtils/Utils.h" -#include -#include -#include - -using namespace o2::its; - -//_____________________________________________________________________ -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::ChipMappingITS::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>(); - mReader = mReaderRaw.get(); - } else { // clusterizer of digits - mReaderMC = std::make_unique(); - 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("ITSClusterComp", &compClusPtr); - - auto rofRecVecPtr = &mROFRecVec; - outTree.Branch("ITSClustersROF", &rofRecVecPtr); - - auto clsLabelsPtr = &mClsLabels; - if (mUseMCTruth && mReaderMC->getDigitsMCTruth()) { - // digit labels are provided directly to clusterer - outTree.Branch("ITSClusterMCTruth", &clsLabelsPtr); - } else { - mUseMCTruth = false; - } - LOG(info) << Class()->GetName() << " | MCTruth: " << (mUseMCTruth ? "ON" : "OFF"); - - outTree.Branch("ITSClusterPatt", &mPatterns); - - std::vector 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("ITSClustersMC2ROF", mc2rofPtr); - } - - // loop over entries of the input tree - while (mReaderMC->readNextEntry()) { - mClusterer.process(1, *mReaderMC.get(), &mCompClus, &mPatterns, &mROFRecVec, &mClsLabels); - } - - 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", "ITS Clusters"); - - size_t max = (i + 1) * maxROframe; - auto lastf = (max < mROFRecVec.size()) ? mROFRecVec.begin() + max : mROFRecVec.end(); - std::vector rofRecBuffer(mROFRecVec.begin() + i * maxROframe, lastf); - std::vector* rofRecPtr = &rofRecBuffer; - outTree.Branch("ITSClustersROF", rofRecPtr); - - auto first = rofRecBuffer[0].getFirstEntry(); - auto last = rofRecBuffer.back().getFirstEntry() + rofRecBuffer.back().getNEntries(); - - std::vector compClusBuffer, *compClusPtr = &compClusBuffer; - compClusBuffer.assign(&mCompClus[first], &mCompClus[last]); - outTree.Branch("ITSClusterComp", &compClusPtr); - outTree.Branch("ITSClusterPatt", &mPatterns); - - for (auto& rof : rofRecBuffer) { - rof.setFirstEntry(rof.getFirstEntry() - first); - } - - outTree.Fill(); - outTree.Write(); -} diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/CookedTracker.cxx b/Detectors/ITSMFT/ITS/reconstruction/src/CookedTracker.cxx deleted file mode 100644 index 5c804f6705dfd..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/src/CookedTracker.cxx +++ /dev/null @@ -1,865 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file CookedTracker.cxx -/// \brief Implementation of the "Cooked Matrix" ITS tracker -/// \author iouri.belikov@cern.ch - -//------------------------------------------------------------------------- -// A stand-alone ITS tracker -// The pattern recongintion based on the "cooked covariance" approach -//------------------------------------------------------------------------- -#include -#include -#include - -#include -#include - -#include - -#include "CommonConstants/MathConstants.h" -#include "DetectorsBase/Propagator.h" -#include "Field/MagneticField.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/TopologyDictionary.h" -#include "ITSReconstruction/CookedTracker.h" -#include "MathUtils/Utils.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" - -using namespace o2::its; -using namespace o2::itsmft; -using namespace o2::constants::math; -using o2::field::MagneticField; -using Label = o2::MCCompLabel; - -/*** Tracking parameters ***/ -// seed "windows" in z and phi: makeSeeds -Float_t CookedTracker::gzWin = 0.33; -Float_t CookedTracker::gminPt = 0.05; -Float_t CookedTracker::mMostProbablePt = o2::track::kMostProbablePt; -// Maximal accepted impact parameters for the seeds -Float_t CookedTracker::gmaxDCAxy = 3.; -Float_t CookedTracker::gmaxDCAz = 3.; -// Layers for the seeding -Int_t CookedTracker::gSeedingLayer1 = 6; -Int_t CookedTracker::gSeedingLayer2 = 4; -Int_t CookedTracker::gSeedingLayer3 = 5; -// Space point resolution -Float_t CookedTracker::gSigma2 = 0.0005 * 0.0005; -// Max accepted chi2 -Float_t CookedTracker::gmaxChi2PerCluster = 20.; -Float_t CookedTracker::gmaxChi2PerTrack = 30.; -// Tracking "road" from layer to layer -Float_t CookedTracker::gRoadY = 0.2; -Float_t CookedTracker::gRoadZ = 0.3; -// Minimal number of attached clusters -Int_t CookedTracker::gminNumberOfClusters = 4; - -const float kPI = 3.14159f; -const float k2PI = 2 * kPI; - -//************************************************ -// TODO: -//************************************************ -// Seeding: -// Precalculate cylidnrical (r,phi) for the clusters; -// use exact r's for the clusters - -CookedTracker::Layer CookedTracker::sLayers[CookedTracker::kNLayers]; - -CookedTracker::CookedTracker(Int_t n) : mNumOfThreads(n), mBz(0.) -{ - //-------------------------------------------------------------------- - // This default constructor needs to be provided - //-------------------------------------------------------------------- - const Double_t klRadius[7] = {2.34, 3.15, 3.93, 19.61, 24.55, 34.39, 39.34}; // tdr6 - - for (Int_t i = 0; i < kNLayers; i++) { - sLayers[i].setR(klRadius[i]); - } -} - -//__________________________________________________________________________ -Label CookedTracker::cookLabel(TrackITSExt& t, Float_t wrong) const -{ - //-------------------------------------------------------------------- - // This function "cooks" a track label. - // A label<0 indicates that some of the clusters are wrongly assigned. - //-------------------------------------------------------------------- - Int_t noc = t.getNumberOfClusters(); - std::map labelOccurence; - - for (int i = noc; i--;) { - const Cluster* c = getCluster(t.getClusterIndex(i)); - Int_t idx = c - &mClusterCache[0] + mFirstInFrame; // Index of this cluster in event - auto labels = mClsLabels->getLabels(idx); - - for (auto lab : labels) { // check all labels of the cluster - if (lab.isEmpty()) { - break; // all following labels will be empty also - } - // was this label already accounted for ? - labelOccurence[lab]++; - } - } - Label lab; - Int_t maxL = 0; // find most encountered label - for (auto [label, count] : labelOccurence) { - if (count <= maxL) { - continue; - } - maxL = count; - lab = label; - } - - if ((1. - Float_t(maxL) / noc) > wrong) { - // change the track ID to negative - lab.setFakeFlag(); - } - // t.SetFakeRatio((1.- Float_t(maxL)/noc)); - return lab; -} - -Double_t CookedTracker::getBz() const -{ - return mBz; -} - -static Double_t f1(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Double_t x3, Double_t y3) -{ - //----------------------------------------------------------------- - // Initial approximation of the track curvature - //----------------------------------------------------------------- - Double_t d = (x2 - x1) * (y3 - y2) - (x3 - x2) * (y2 - y1); - Double_t a = - 0.5 * ((y3 - y2) * (y2 * y2 - y1 * y1 + x2 * x2 - x1 * x1) - (y2 - y1) * (y3 * y3 - y2 * y2 + x3 * x3 - x2 * x2)); - Double_t b = - 0.5 * ((x2 - x1) * (y3 * y3 - y2 * y2 + x3 * x3 - x2 * x2) - (x3 - x2) * (y2 * y2 - y1 * y1 + x2 * x2 - x1 * x1)); - - Double_t xr = TMath::Abs(d / (d * x1 - a)), yr = TMath::Abs(d / (d * y1 - b)); - - Double_t crv = xr * yr / sqrt(xr * xr + yr * yr); - if (d > 0) { - crv = -crv; - } - - return crv; -} - -static Double_t f2(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Double_t x3, Double_t y3) -{ - //----------------------------------------------------------------- - // Initial approximation of the x-coordinate of the center of curvature - //----------------------------------------------------------------- - - Double_t k1 = (y2 - y1) / (x2 - x1), k2 = (y3 - y2) / (x3 - x2); - Double_t x0 = 0.5 * (k1 * k2 * (y1 - y3) + k2 * (x1 + x2) - k1 * (x2 + x3)) / (k2 - k1); - - return x0; -} - -static Double_t f3(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Double_t z1, Double_t z2) -{ - //----------------------------------------------------------------- - // Initial approximation of the tangent of the track dip angle - //----------------------------------------------------------------- - return (z1 - z2) / sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); -} - -o2::its::TrackITSExt CookedTracker::cookSeed(const Point3Df& r1, Point3Df& r2, const Point3Df& tr3, float rad2, float rad3, float_t alpha, float_t bz) -// const Float_t r1[4], const Float_t r2[4], const Float_t tr3[4], Double_t alpha, Double_t bz) -{ - //-------------------------------------------------------------------- - // This is the main cooking function. - // Creates seed parameters out of provided clusters. - //-------------------------------------------------------------------- - - Double_t ca = TMath::Cos(alpha), sa = TMath::Sin(alpha); - Double_t x1 = r1.X() * ca + r1.Y() * sa, y1 = -r1.X() * sa + r1.Y() * ca, z1 = r1.Z(); - Double_t x2 = r2.X() * ca + r2.Y() * sa, y2 = -r2.X() * sa + r2.Y() * ca, z2 = r2.Z(); - Double_t x3 = tr3.X(), y3 = tr3.Y(), z3 = tr3.Z(); - - std::array par; - par[0] = y3; - par[1] = z3; - Double_t crv = f1(x1, y1, x2, y2, x3, y3); // curvature - Double_t x0 = f2(x1, y1, x2, y2, x3, y3); // x-coordinate of the center - Double_t tgl12 = f3(x1, y1, x2, y2, z1, z2); - Double_t tgl23 = f3(x2, y2, x3, y3, z2, z3); - - Double_t sf = crv * (x3 - x0); // FIXME: sf must never be >= kAlmost1 - par[2] = sf; - - par[3] = 0.5 * (tgl12 + tgl23); - par[4] = (TMath::Abs(bz) < Almost0) ? 1 / CookedTracker::getMostProbablePt() : crv / (bz * B2C); - - std::array cov; - /* - for (Int_t i=0; i<15; i++) cov[i]=0.; - cov[0] =gSigma2*10; - cov[2] =gSigma2*10; - cov[5] =0.007*0.007*10; //FIXME all these lines - cov[9] =0.007*0.007*10; - cov[14]=0.1*0.1*10; - */ - const Double_t dlt = 0.0005; - Double_t fy = 1. / (rad2 - rad3); - Double_t tz = fy; - const auto big = sqrt(o2::constants::math::VeryBig); - auto cy = big; - if (TMath::Abs(bz) >= Almost0) { - auto tmp = dlt * bz * B2C; - cy = (f1(x1, y1, x2, y2 + dlt, x3, y3) - crv) / tmp; - cy *= 20; // FIXME: MS contribution to the cov[14] - } - Double_t s2 = gSigma2; - - cov[0] = s2; - cov[1] = 0.; - cov[2] = s2; - cov[3] = s2 * fy; - cov[4] = 0.; - cov[5] = s2 * fy * fy; - cov[6] = 0.; - cov[7] = s2 * tz; - cov[8] = 0.; - cov[9] = s2 * tz * tz; - cov[10] = s2 * cy; - cov[11] = 0.; - cov[12] = s2 * fy * cy; - cov[13] = 0.; - cov[14] = s2 * cy * cy; - - return o2::its::TrackITSExt(x3, alpha, par, cov); -} - -void CookedTracker::makeSeeds(std::vector& seeds, Int_t first, Int_t last) -{ - //-------------------------------------------------------------------- - // This is the main pattern recongition function. - // Creates seeds out of two clusters and another point. - //-------------------------------------------------------------------- - const float zv = getZ(); - - Layer& layer1 = sLayers[gSeedingLayer1]; - Layer& layer2 = sLayers[gSeedingLayer2]; - Layer& layer3 = sLayers[gSeedingLayer3]; - - auto bz = getBz(); - const Double_t maxC = (TMath::Abs(bz) < Almost0) ? 0.03 : TMath::Abs(bz * B2C / gminPt); - const Double_t kpWinC = TMath::ASin(0.5 * maxC * layer1.getR()) - TMath::ASin(0.5 * maxC * layer2.getR()); - const Double_t kpWinD = 2 * (TMath::ASin(gmaxDCAxy / layer2.getR()) - TMath::ASin(gmaxDCAxy / layer1.getR())); - const Double_t kpWin = std::max(kpWinC, kpWinD); - - for (Int_t n1 = first; n1 < last; n1++) { - const Cluster* c1 = layer1.getCluster(n1); - // - //auto lab = (mClsLabels->getLabels(c1 - &mClusterCache[0] + mFirstInFrame))[0]; - // - auto xyz1 = c1->getXYZGloRot(*mGeom); - auto z1 = xyz1.Z(); - auto r1 = xyz1.rho(); - - auto phi1 = layer1.getClusterPhi(n1); - auto tgl = std::abs((z1 - zv) / r1); - - auto zr2 = zv + layer2.getR() / r1 * (z1 - zv); - auto phir2 = phi1; - auto dz2 = gzWin * (1 + 2 * tgl); - - std::vector selected2; - float dy2 = kpWin * layer2.getR(); - layer2.selectClusters(selected2, phir2, dy2, zr2, dz2); - for (auto n2 : selected2) { - const Cluster* c2 = layer2.getCluster(n2); - // - //if ((mClsLabels->getLabels(c2 - &mClusterCache[0] + mFirstInFrame))[0] != lab) continue; - // - auto xyz2 = c2->getXYZGloRot(*mGeom); - auto z2 = xyz2.Z(); - auto r2 = xyz2.rho(); - - auto dx = xyz2.X() - xyz1.X(), dy = xyz2.Y() - xyz1.Y(); - auto d = (dx * xyz1.Y() - dy * xyz1.X()) / TMath::Sqrt(dx * dx + dy * dy); - auto phir3 = phi1 + TMath::ASin(d / r1) - TMath::ASin(d / layer3.getR()); - - auto zr3 = z1 + (layer3.getR() - r1) / (r2 - r1) * (z2 - z1); - auto dz3 = 0.5f * dz2; - - std::vector selected3; - float dy3 = 0.1 * kpWin * layer3.getR(); //Fixme - layer3.selectClusters(selected3, phir3, dy3, zr3, dz3); - for (auto n3 : selected3) { - const Cluster* c3 = layer3.getCluster(n3); - // - //if ((mClsLabels->getLabels(c3 - &mClusterCache[0] + mFirstInFrame))[0] != lab) continue; - // - auto xyz3 = c3->getXYZGloRot(*mGeom); - auto z3 = xyz3.Z(); - auto r3 = xyz3.rho(); - - zr3 = z1 + (r3 - r1) / (r2 - r1) * (z2 - z1); - if (std::abs(z3 - zr3) > 0.2 * dz3) { - continue; - } - - const Point3Df& txyz2 = c2->getXYZ(); // tracking coordinates - - TrackITSExt seed = cookSeed(xyz1, xyz3, txyz2, layer2.getR(), layer3.getR(), layer2.getAlphaRef(n2), getBz()); - - float ip[2]; - seed.getImpactParams(getX(), getY(), getZ(), getBz(), ip); - if (TMath::Abs(ip[0]) > gmaxDCAxy) { - continue; - } - if (TMath::Abs(ip[1]) > gmaxDCAz) { - continue; - } - { - Double_t xx0 = 0.008; // Rough layer thickness - Double_t radl = 9.36; // Radiation length of Si [cm] - Double_t rho = 2.33; // Density of Si [g/cm^3] - if (!seed.correctForMaterial(xx0, xx0 * radl * rho, kTRUE)) { - continue; - } - } - seed.setClusterIndex(gSeedingLayer1, n1); - seed.setClusterIndex(gSeedingLayer3, n3); - seed.setClusterIndex(gSeedingLayer2, n2); - seeds.push_back(seed); - } - } - } - /* - for (Int_t n1 = 0; n1 < nClusters1; n1++) { - Cluster* c1 = layer1.getCluster(n1); - ((Cluster*)c1)->goToFrameTrk(); - } - for (Int_t n2 = 0; n2 < nClusters2; n2++) { - Cluster* c2 = layer2.getCluster(n2); - ((Cluster*)c2)->goToFrameTrk(); - } - for (Int_t n3 = 0; n3 < nClusters3; n3++) { - Cluster* c3 = layer3.getCluster(n3); - ((Cluster*)c3)->goToFrameTrk(); - } - */ -} - -void CookedTracker::trackSeeds(std::vector& seeds) -{ - //-------------------------------------------------------------------- - // Loop over a subset of track seeds - //-------------------------------------------------------------------- - std::vector used[gSeedingLayer2]; - std::vector selec[gSeedingLayer2]; - for (Int_t l = gSeedingLayer2 - 1; l >= 0; l--) { - Int_t n = sLayers[l].getNumberOfClusters(); - used[l].resize(n, false); - selec[l].reserve(n / 100); - } - - for (auto& track : seeds) { - auto x = track.getX(); - auto y = track.getY(); - Float_t phi = track.getAlpha() + TMath::ATan2(y, x); - o2::math_utils::bringTo02Pi(phi); - float ip[2]; - track.getImpactParams(getX(), getY(), getZ(), getBz(), ip); - - auto z = track.getZ(); - auto crv = track.getCurvature(getBz()); - auto tgl = track.getTgl(); - Float_t r1 = sLayers[gSeedingLayer2].getR(); - - for (Int_t l = gSeedingLayer2 - 1; l >= 0; l--) { - Float_t r2 = sLayers[l].getR(); - selec[l].clear(); - if (TMath::Abs(ip[0]) > r2) { - break; - } - if (TMath::Abs(crv) < gRoadY / (0.5 * r1 * 0.5 * r1)) { - phi += TMath::ASin(ip[0] / r2) - TMath::ASin(ip[0] / r1); - z += tgl * (TMath::Sqrt(r2 * r2 - ip[0] * ip[0]) - TMath::Sqrt(r1 * r1 - ip[0] * ip[0])); - } else { // Fixme - phi += 0.5 * crv * (r2 - r1); - z += tgl / (0.5 * crv) * (TMath::ASin(0.5 * crv * r2) - TMath::ASin(0.5 * crv * r1)); - } - sLayers[l].selectClusters(selec[l], phi, gRoadY, z, gRoadZ * (1 + 2 * std::abs(tgl))); - r1 = r2; - } - - TrackITSExt best(track); - - Int_t volID = -1; - for (auto& ci3 : selec[3]) { - TrackITSExt t3(track); - if (used[3][ci3]) { - continue; - } - if (!attachCluster(volID, 3, ci3, t3, track)) { - continue; - } - if (t3.isBetter(best, gmaxChi2PerTrack)) { - best = t3; - } - - for (auto& ci2 : selec[2]) { - TrackITSExt t2(t3); - if (used[2][ci2]) { - continue; - } - if (!attachCluster(volID, 2, ci2, t2, t3)) { - continue; - } - if (t2.isBetter(best, gmaxChi2PerTrack)) { - best = t2; - } - - for (auto& ci1 : selec[1]) { - TrackITSExt t1(t2); - if (used[1][ci1]) { - continue; - } - if (!attachCluster(volID, 1, ci1, t1, t2)) { - continue; - } - if (t1.isBetter(best, gmaxChi2PerTrack)) { - best = t1; - } - - for (auto& ci0 : selec[0]) { - TrackITSExt t0(t1); - if (used[0][ci0]) { - continue; - } - if (!attachCluster(volID, 0, ci0, t0, t1)) { - continue; - } - if (t0.isBetter(best, gmaxChi2PerTrack)) { - best = t0; - } - volID = -1; - } - } - } - } - - if (best.getNumberOfClusters() >= gminNumberOfClusters) { - Int_t noc = best.getNumberOfClusters(); - for (Int_t ic = 3; ic < noc; ic++) { - Int_t index = best.getClusterIndex(ic); - Int_t l = (index & 0xf0000000) >> 28, c = (index & 0x0fffffff); - used[l][c] = true; - } - } - track = best; - } -} - -std::vector CookedTracker::trackInThread(Int_t first, Int_t last) -{ - //-------------------------------------------------------------------- - // This function is passed to a tracking thread - //-------------------------------------------------------------------- - std::vector seeds; - seeds.reserve(last - first + 1); - - for (const auto& vtx : *mVertices) { - mX = vtx.getX(); - mY = vtx.getY(); - mZ = vtx.getZ(); - makeSeeds(seeds, first, last); - } - - std::sort(seeds.begin(), seeds.end()); - - trackSeeds(seeds); - - makeBackPropParam(seeds); - - return seeds; -} - -void CookedTracker::process(gsl::span const& clusters, - gsl::span::iterator& pattIt, - const o2::itsmft::TopologyDictionary* dict, - TrackInserter& inserter, - o2::itsmft::ROFRecord& rof) -{ - //-------------------------------------------------------------------- - // This is the main tracking function - //-------------------------------------------------------------------- - if (mVertices == nullptr || mVertices->empty()) { - LOG(info) << "Not a single primary vertex provided. Skipping...\n"; - return; - } - LOG(info) << "\n CookedTracker::process(), number of threads: " << mNumOfThreads; - - auto start = std::chrono::system_clock::now(); - - mFirstInFrame = rof.getFirstEntry(); - - mClusterCache.reserve(rof.getNEntries()); - auto clusters_in_frame = rof.getROFData(clusters); - for (const auto& comp : clusters_in_frame) { - - auto pattID = comp.getPatternID(); - o2::math_utils::Point3D locXYZ; - float sigmaY2 = gSigma2, sigmaZ2 = gSigma2; - if (pattID != itsmft::CompCluster::InvalidPatternID) { - sigmaY2 = gSigma2; //dict.getErr2X(pattID); - sigmaZ2 = gSigma2; //dict.getErr2Z(pattID); - if (!dict->isGroup(pattID)) { - locXYZ = dict->getClusterCoordinates(comp); - } else { - o2::itsmft::ClusterPattern patt(pattIt); - locXYZ = dict->getClusterCoordinates(comp, patt); - } - } else { - o2::itsmft::ClusterPattern patt(pattIt); - locXYZ = dict->getClusterCoordinates(comp, patt, false); - } - auto sensorID = comp.getSensorID(); - // Inverse transformation to the local --> tracking - auto trkXYZ = mGeom->getMatrixT2L(sensorID) ^ locXYZ; - - Cluster c; - c.setSensorID(sensorID); - c.setPos(trkXYZ); - c.setErrors(sigmaY2, sigmaZ2, 0.f); - mClusterCache.push_back(c); - } - - auto nClFrame = loadClusters(); - - auto end = std::chrono::system_clock::now(); - std::chrono::duration diff = end - start; - LOG(info) << "Loading clusters: " << nClFrame << " in a single frame : " << diff.count() << " s"; - - start = end; - - auto [first, number] = processLoadedClusters(inserter); - rof.setFirstEntry(first); - rof.setNEntries(number); - - unloadClusters(); - end = std::chrono::system_clock::now(); - diff = end - start; - LOG(info) << "Processing time/clusters for single frame : " << diff.count() << " / " << nClFrame << " s"; - - start = end; -} - -std::tuple CookedTracker::processLoadedClusters(TrackInserter& inserter) -{ - //-------------------------------------------------------------------- - // This is the main tracking function for single frame, it is assumed that only clusters - // which may contribute to this frame is loaded - //-------------------------------------------------------------------- - Int_t numOfClusters = sLayers[gSeedingLayer1].getNumberOfClusters(); - if (!numOfClusters) { - return {0, 0}; - } - - std::vector>> futures(mNumOfThreads); - std::vector> seedArray(mNumOfThreads); - - for (Int_t t = 0, first = 0; t < mNumOfThreads; t++) { - Int_t rem = t < (numOfClusters % mNumOfThreads) ? 1 : 0; - Int_t last = first + (numOfClusters / mNumOfThreads) + rem; - futures[t] = std::async(std::launch::async, &CookedTracker::trackInThread, this, first, last); - first = last; - } - Int_t nSeeds = 0, ngood = 0; - int nAllTracks = 0, nTracks = 0; - for (Int_t t = 0; t < mNumOfThreads; t++) { - seedArray[t] = futures[t].get(); - nSeeds += seedArray[t].size(); - for (auto& track : seedArray[t]) { - if (track.getNumberOfClusters() < gminNumberOfClusters) { - continue; - } - - o2::dataformats::VertexBase vtx; - track.propagateToDCA(vtx, getBz()); - - nAllTracks = inserter(track); - nTracks++; - if (mTrkLabels) { - Label label = cookLabel(track, 0.); // For comparison only - if (label.getTrackID() >= 0) { - ngood++; - } - // the inserter returns the size of the track vector, the index of the last - // inserted track is thus n - 1 - mTrkLabels->emplace_back(label); - } - } - } - - if (nSeeds) { - LOG(info) << "Found tracks: " << nTracks; - LOG(info) << "CookedTracker::processLoadedClusters(), good_tracks:/seeds: " << ngood << '/' << nSeeds << "-> " - << Float_t(ngood) / nSeeds << '\n'; - } - // returning index of the first track and the number of add tracks - // inserted in this call - return {nAllTracks - nTracks, nTracks}; -} - -//____________________________________________________________ -void CookedTracker::makeBackPropParam(std::vector& seeds) const -{ - // refit in backward direction - for (auto& track : seeds) { - if (track.getNumberOfClusters() < gminNumberOfClusters) { - continue; - } - makeBackPropParam(track); - } -} - -//____________________________________________________________ -bool CookedTracker::makeBackPropParam(TrackITSExt& track) const -{ - // refit in backward direction - auto backProp = track.getParamOut(); - backProp = track; - backProp.resetCovariance(); - auto propagator = o2::base::Propagator::Instance(); - - Int_t noc = track.getNumberOfClusters(); - for (int ic = noc; ic--;) { // cluster indices are stored in inward direction - Int_t index = track.getClusterIndex(ic); - const Cluster* c = getCluster(index); - float alpha = mGeom->getSensorRefAlpha(c->getSensorID()); - if (!backProp.rotate(alpha)) { - return false; - } - if (!propagator->PropagateToXBxByBz(backProp, c->getX())) { - return false; - } - if (!backProp.update(static_cast&>(*c))) { - return false; - } - } - track.getParamOut() = backProp; - return true; -} - -int CookedTracker::loadClusters() -{ - //-------------------------------------------------------------------- - // This function reads the ITSU clusters from the tree, - // sort them, distribute over the internal tracker arrays, etc - //-------------------------------------------------------------------- - - if (mClusterCache.empty()) { - return 0; - } - - for (const auto& c : mClusterCache) { - Int_t layer = mGeom->getLayer(c.getSensorID()); - sLayers[layer].insertCluster(&c); - } - - std::vector> fut; - for (Int_t l = 0; l < kNLayers; l += mNumOfThreads) { - for (Int_t t = 0; t < mNumOfThreads; t++) { - if (l + t >= kNLayers) { - break; - } - auto f = std::async(std::launch::async, &CookedTracker::Layer::init, sLayers + (l + t)); - fut.push_back(std::move(f)); - } - for (size_t t = 0; t < fut.size(); t++) { - fut[t].wait(); - } - } - - return mClusterCache.size(); -} - -void CookedTracker::unloadClusters() -{ - //-------------------------------------------------------------------- - // This function unloads ITSU clusters from the RAM - //-------------------------------------------------------------------- - mClusterCache.clear(); - for (Int_t i = 0; i < kNLayers; i++) { - sLayers[i].unloadClusters(); - } -} - -const Cluster* CookedTracker::getCluster(Int_t index) const -{ - //-------------------------------------------------------------------- - // Return pointer to a given cluster - //-------------------------------------------------------------------- - Int_t l = (index & 0xf0000000) >> 28; - Int_t c = (index & 0x0fffffff) >> 00; - return sLayers[l].getCluster(c); -} - -CookedTracker::Layer::Layer() : mR(0) -{ - //-------------------------------------------------------------------- - // This default constructor needs to be provided - //-------------------------------------------------------------------- -} - -void CookedTracker::Layer::init() -{ - //-------------------------------------------------------------------- - // Sort clusters and cache their reference plane info in a thread - //-------------------------------------------------------------------- - std::sort(std::begin(mClusters), std::end(mClusters), - [](const Cluster* c1, const Cluster* c2) { return (c1->getZ() < c2->getZ()); }); - - Double_t r = 0.; - Int_t m = mClusters.size(); - for (Int_t i = 0; i < m; i++) { - const Cluster* c = mClusters[i]; - // Float_t xRef, aRef; - // mGeom->getSensorXAlphaRefPlane(c->getSensorID(),xRef, aRef); - mAlphaRef.push_back(mGeom->getSensorRefAlpha(c->getSensorID())); - auto xyz = c->getXYZGloRot(*mGeom); - r += xyz.rho(); - Float_t phi = xyz.Phi(); - o2::math_utils::bringTo02Pi(phi); - mPhi.push_back(phi); - Int_t s = phi * (int)kNSectors / k2PI; - mSectors[s < kNSectors ? s : kNSectors - 1].emplace_back(i, c->getZ()); - } - - if (m) { - mR = r / m; - } -} - -void CookedTracker::Layer::unloadClusters() -{ - //-------------------------------------------------------------------- - // Unload clusters from this layer - //-------------------------------------------------------------------- - mClusters.clear(); - mAlphaRef.clear(); - mPhi.clear(); - for (Int_t s = 0; s < kNSectors; s++) { - mSectors[s].clear(); - } -} - -Bool_t CookedTracker::Layer::insertCluster(const Cluster* c) -{ - //-------------------------------------------------------------------- - // This function inserts a cluster to this layer - //-------------------------------------------------------------------- - mClusters.push_back(c); - return kTRUE; -} - -Int_t CookedTracker::Layer::findClusterIndex(Float_t z) const -{ - //-------------------------------------------------------------------- - // This function returns the index of the first cluster with its fZ >= "z". - //-------------------------------------------------------------------- - auto found = std::upper_bound(std::begin(mClusters), std::end(mClusters), z, - [](Float_t zc, const Cluster* c) { return (zc < c->getZ()); }); - return found - std::begin(mClusters); -} - -void CookedTracker::Layer::selectClusters(std::vector& selec, Float_t phi, Float_t dy, Float_t z, Float_t dz) -{ - //-------------------------------------------------------------------- - // This function selects clusters within the "road" - //-------------------------------------------------------------------- - Float_t zMin = z - dz; - Float_t zMax = z + dz; - - o2::math_utils::bringTo02Pi(phi); - - Float_t dphi = dy / mR; - - int smin = (phi - dphi) / k2PI * (int)kNSectors; - int ds = (phi + dphi) / k2PI * (int)kNSectors - smin + 1; - - smin = (smin + kNSectors) % kNSectors; - - for (int is = 0; is < ds; is++) { - Int_t s = (smin + is) % kNSectors; - - auto cmp = [](Float_t zc, std::pair p) { return (zc < p.second); }; - auto imin = std::upper_bound(std::begin(mSectors[s]), std::end(mSectors[s]), zMin, cmp); - auto imax = std::upper_bound(imin, std::end(mSectors[s]), zMax, cmp); - for (; imin != imax; imin++) { - auto [i, zz] = *imin; - auto cdphi = std::abs(mPhi[i] - phi); - if (cdphi > dphi) { - if (cdphi > kPI) { - cdphi = k2PI - cdphi; - } - if (cdphi > dphi) { - continue; // check in Phi - } - } - selec.push_back(i); - } - } -} - -Bool_t CookedTracker::attachCluster(Int_t& volID, Int_t nl, Int_t ci, TrackITSExt& t, const TrackITSExt& o) const -{ - //-------------------------------------------------------------------- - // Try to attach a clusters with index ci to running track hypothesis - //-------------------------------------------------------------------- - Layer& layer = sLayers[nl]; - const Cluster* c = layer.getCluster(ci); - - Int_t vid = c->getSensorID(); - - if (vid != volID) { - volID = vid; - t = o; - Double_t alpha = layer.getAlphaRef(ci); - if (!t.propagate(alpha, c->getX(), getBz())) { - return kFALSE; - } - } - - Double_t chi2 = t.getPredictedChi2(*c); - if (chi2 > gmaxChi2PerCluster) { - return kFALSE; - } - - if (!t.update(*c, chi2)) { - return kFALSE; - } - t.setClusterIndex(nl, ci); - - Double_t xx0 = (nl > 2) ? 0.008 : 0.003; // Rough layer thickness - Double_t x0 = 9.36; // Radiation length of Si [cm] - Double_t rho = 2.33; // Density of Si [g/cm^3] - t.correctForMaterial(xx0, xx0 * x0 * rho, kTRUE); - return kTRUE; -} - -void CookedTracker::setGeometry(o2::its::GeometryTGeo* geom) -{ - /// attach geometry interface - mGeom = geom; - for (Int_t i = 0; i < kNLayers; i++) { - sLayers[i].setGeometry(geom); - } -} diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/FastMultEst.cxx b/Detectors/ITSMFT/ITS/reconstruction/src/FastMultEst.cxx deleted file mode 100644 index c547996c6f356..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/src/FastMultEst.cxx +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file FastMultEst.h -/// \brief Fast multiplicity estimator for ITS -/// \author ruben.shahoyan@cern.ch - -#include "ITSReconstruction/FastMultEst.h" -#include "ITSMFTBase/DPLAlpideParam.h" -#include "Framework/Logger.h" -#include -#include -#include - -using namespace o2::its; - -bool FastMultEst::sSeedSet = false; - -///______________________________________________________ -FastMultEst::FastMultEst() -{ - if (!sSeedSet && FastMultEstConfig::Instance().cutRandomFraction > 0.f) { - sSeedSet = true; - if (FastMultEstConfig::Instance().randomSeed > 0) { - gRandom->SetSeed(FastMultEstConfig::Instance().randomSeed); - } else if (FastMultEstConfig::Instance().randomSeed < 0) { - gRandom->SetSeed(std::time(nullptr) % 0xffff); - } - } -} - -///______________________________________________________ -/// find multiplicity for given set of clusters -void FastMultEst::fillNClPerLayer(const gsl::span& clusters) -{ - int lr = FastMultEst::NLayers - 1, nchAcc = o2::itsmft::ChipMappingITS::getNChips() - o2::itsmft::ChipMappingITS::getNChipsPerLr(lr); - std::memset(&nClPerLayer[0], 0, sizeof(int) * FastMultEst::NLayers); - for (int i = clusters.size(); i--;) { // profit from clusters being ordered in chip increasing order - while (clusters[i].getSensorID() < nchAcc) { - assert(lr >= 0); - nchAcc -= o2::itsmft::ChipMappingITS::getNChipsPerLr(--lr); - } - nClPerLayer[lr]++; - } -} - -///______________________________________________________ -/// find multiplicity for given number of clusters per layer -float FastMultEst::processNoiseFree(const std::array ncl) -{ - // we assume that on the used layers the observed number of clusters is defined by the - // the noise ~ nu * Nchips and contribution from the signal tracks Ntr*mAccCorr - const auto& conf = FastMultEstConfig::Instance(); - - float mat[3] = {0}, b[2] = {0}; - nLayersUsed = 0; - for (int il = conf.firstLayer; il <= conf.lastLayer; il++) { - if (ncl[il] > 0) { - int nch = o2::itsmft::ChipMappingITS::getNChipsPerLr(il); - float err2i = 1. / ncl[il]; - float m2n = nch * err2i; - mat[0] += err2i * conf.accCorr[il] * conf.accCorr[il]; - mat[2] += nch * m2n; - mat[1] += conf.accCorr[il] * m2n; // non-diagonal element - b[0] += conf.accCorr[il]; - b[1] += nch; - nLayersUsed++; - } - } - mult = noisePerChip = chi2 = -1; - float det = mat[0] * mat[2] - mat[1] * mat[1]; - if (nLayersUsed < 2 || std::abs(det) < 1e-15) { - return -1; - } - float detI = 1. / det; - mult = detI * (b[0] * mat[2] - b[1] * mat[1]); - noisePerChip = detI * (b[1] * mat[0] - b[0] * mat[1]); - cov[0] = mat[2] * detI; - cov[2] = mat[0] * detI; - cov[1] = -mat[1] * detI; - chi2 = 0.; - for (int il = conf.firstLayer; il <= conf.lastLayer; il++) { - if (ncl[il] > 0) { - int nch = o2::itsmft::ChipMappingITS::getNChipsPerLr(il); - float diff = mult * conf.accCorr[il] + nch * noisePerChip - ncl[il]; - chi2 += diff * diff / ncl[il]; - } - } - chi2 = nLayersUsed > 2 ? chi2 / (nLayersUsed - 2) : 0.; - return mult > 0 ? mult : 0; -} - -///______________________________________________________ -/// find multiplicity for given number of clusters per layer with mean noise imposed -float FastMultEst::processNoiseImposed(const std::array ncl) -{ - // we assume that on the used layers the observed number of clusters is defined by the - // the noise ~ nu * Nchips and contribution from the signal tracks Ntr*conf.accCorr - // - const auto& conf = FastMultEstConfig::Instance(); - float accSum = 0., accWSum = 0., noiseSum = 0.; - nLayersUsed = 0; - for (int il = conf.firstLayer; il <= conf.lastLayer; il++) { - if (ncl[il] > 0) { - float err = 1. / ncl[il]; - accSum += conf.accCorr[il]; - accWSum += conf.accCorr[il] * conf.accCorr[il] * err; - noiseSum += o2::itsmft::ChipMappingITS::getNChipsPerLr(il) * conf.accCorr[il] * err; - nLayersUsed++; - } - } - mult = 0; - if (nLayersUsed) { - mult = (accSum - noisePerChip * noiseSum) / accWSum; - } - return mult; -} - -int FastMultEst::selectROFs(const gsl::span rofs, const gsl::span clus, - const gsl::span trig, std::vector& sel) -{ - int nrof = rofs.size(), nsel = 0; - const auto& multEstConf = FastMultEstConfig::Instance(); // parameters for mult estimation and cuts - sel.clear(); - sel.resize(nrof, true); // by default select all - lastRandomSeed = gRandom->GetSeed(); - if (multEstConf.isMultCutRequested()) { - for (uint32_t irof = 0; irof < nrof; irof++) { - nsel += sel[irof] = multEstConf.isPassingMultCut(process(rofs[irof].getROFData(clus))); - } - } else { - nsel = nrof; - } - using IdNT = std::pair; - if (multEstConf.cutRandomFraction > 0.) { - int ntrig = trig.size(), currTrig = 0; - if (multEstConf.preferTriggered) { - const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); - std::vector nTrigROF; - nTrigROF.reserve(nrof); - for (uint32_t irof = 0; irof < nrof; irof++) { - if (sel[irof]) { - if (nsel && gRandom->Rndm() < multEstConf.cutRandomFraction) { - nsel--; - } - auto irROF = rofs[irof].getBCData(); - while (currTrig < ntrig && trig[currTrig].ir < irROF) { // triggers are sorted, jump to 1st one not less than current ROF - currTrig++; - } - auto& trof = nTrigROF.emplace_back(irof, 0); - irROF += alpParams.roFrameLengthInBC; - while (currTrig < ntrig && trig[currTrig].ir < irROF) { - trof.second++; - currTrig++; - } - } - } - if (nsel > 0) { - sort(nTrigROF.begin(), nTrigROF.end(), [](const IdNT& a, const IdNT& b) { return a.second > b.second; }); // order in number of triggers - auto last = nTrigROF.begin() + nsel; - sort(nTrigROF.begin(), last, [](const IdNT& a, const IdNT& b) { return a.first < b.first; }); // order in ROF ID first nsel ROFs - } - for (int i = nsel; i < int(nTrigROF.size()); i++) { // reject ROFs in the tail - sel[nTrigROF[i].first] = false; - } - } else { // dummy random rejection - for (int irof = 0; irof < nrof; irof++) { - if (sel[irof]) { - float sr = gRandom->Rndm(); - if (gRandom->Rndm() < multEstConf.cutRandomFraction) { - sel[irof] = false; - nsel--; - } - } - } - } - } - LOGP(debug, "NSel = {} of {} rofs Seeds: before {} after {}", nsel, nrof, lastRandomSeed, gRandom->GetSeed()); - - return nsel; -} diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/ITSReconstructionLinkDef.h b/Detectors/ITSMFT/ITS/reconstruction/src/ITSReconstructionLinkDef.h index c93cf03d0ed3d..3bc8ee0f5403b 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/src/ITSReconstructionLinkDef.h +++ b/Detectors/ITSMFT/ITS/reconstruction/src/ITSReconstructionLinkDef.h @@ -15,13 +15,6 @@ #pragma link off all classes; #pragma link off all functions; -#pragma link C++ class o2::its::ClustererTask + ; -#pragma link C++ class o2::its::CookedTracker + ; - #pragma link C++ class o2::its::RecoGeomHelper + ; -#pragma link C++ class o2::its::FastMultEst + ; -#pragma link C++ class o2::its::FastMultEstConfig + ; -#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::its::FastMultEstConfig> + ; - #endif diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/RecoGeomHelper.cxx b/Detectors/ITSMFT/ITS/reconstruction/src/RecoGeomHelper.cxx index 8f2efef0b34cd..712ec6a022d16 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/src/RecoGeomHelper.cxx +++ b/Detectors/ITSMFT/ITS/reconstruction/src/RecoGeomHelper.cxx @@ -229,9 +229,9 @@ void RecoGeomHelper::RecoLayer::print() const } //_____________________________________________________________________ -void RecoGeomHelper::init() +void RecoGeomHelper::init(int minLayer, int maxLayer) { - for (int il = int(layers.size()); il--;) { + for (int il = maxLayer; --il >= minLayer;) { auto& lr = layers[il]; lr.id = il; lr.init(); diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/TrivialVertexer.cxx b/Detectors/ITSMFT/ITS/reconstruction/src/TrivialVertexer.cxx deleted file mode 100644 index cb7f1eeacb02e..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/src/TrivialVertexer.cxx +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file TrivialVertexer.cxx -/// \brief Implementation of the ITS trivial vertex finder - -#include - -#include "TFile.h" -#include "TTree.h" - -#include "FairMCEventHeader.h" -#include - -#include "ITSReconstruction/TrivialVertexer.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" - -using namespace o2::itsmft; -using namespace o2::its; - -using Point3Df = o2::math_utils::Point3D; - -TrivialVertexer::TrivialVertexer() = default; - -TrivialVertexer::~TrivialVertexer() -{ - if (mHeader) - delete mHeader; - if (mTree) - delete mTree; - if (mFile) - delete mFile; -} - -Bool_t TrivialVertexer::openInputFile(const Char_t* fname) -{ - mFile = TFile::Open(fname, "old"); - if (!mFile) { - LOG(error) << "TrivialVertexer::openInputFile() : " - << "Cannot open the input file !"; - return kFALSE; - } - mTree = (TTree*)mFile->Get("o2sim"); - if (!mTree) { - LOG(error) << "TrivialVertexer::openInputFile() : " - << "Cannot get the input tree !"; - return kFALSE; - } - Int_t rc = mTree->SetBranchAddress("MCEventHeader.", &mHeader); - if (rc != 0) { - LOG(error) << "TrivialVertexer::openInputFile() : " - << "Cannot get the input branch ! rc=" << rc; - return kFALSE; - } - return kTRUE; -} - -void TrivialVertexer::process(const std::vector& clusters, std::vector>& vertices) -{ - if (mClsLabels == nullptr) { - LOG(info) << "TrivialVertexer::process() : " - << "No cluster labels available ! Running with a default MC vertex..."; - vertices.emplace_back(std::array{0., 0., 0.}); - return; - } - - if (mTree == nullptr) { - LOG(info) << "TrivialVertexer::process() : " - << "No MC information available ! Running with a default MC vertex..."; - vertices.emplace_back(std::array{0., 0., 0.}); - return; - } - - Int_t lastEventID = 0; - Int_t firstEventID = std::numeric_limits::max(); - - // Find the first and last MC event within this TF - for (Int_t i = 0; i < clusters.size(); ++i) { - auto mclab = (mClsLabels->getLabels(i))[0]; - if (mclab.getTrackID() == -1) - continue; // noise - auto id = mclab.getEventID(); - if (id < firstEventID) - firstEventID = id; - if (id > lastEventID) - lastEventID = id; - } - - for (Int_t mcEv = firstEventID; mcEv <= lastEventID; ++mcEv) { - mTree->GetEvent(mcEv); - Double_t vx = mHeader->GetX(); - Double_t vy = mHeader->GetY(); - Double_t vz = mHeader->GetZ(); - vertices.emplace_back(std::array{vx, vy, vz}); - LOG(info) << "TrivialVertexer::process() : " - << "MC event #" << mcEv << " with vertex (" << vx << ',' << vy << ',' << vz << ')'; - } -} diff --git a/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V3Cage.h b/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V3Cage.h index e90f0cfeb0aed..7844f42601a47 100644 --- a/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V3Cage.h +++ b/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V3Cage.h @@ -113,6 +113,20 @@ class V3Cage : public V11Geometry /// \param mgr The GeoManager (used only to get the proper material) TGeoVolume* createCageClosingCross(const TGeoManager* mgr = gGeoManager); + /// Creates and places the MFT rails inside the Cage + /// \param mother The mother volume to place the rails into + /// \param mgr The GeoManager (used only to get the proper material) + void createAndPlaceMFTRailsInsideCage(TGeoVolume* mother, const TGeoManager* mgr = gGeoManager); + + /// Creates a pair of MFT rails inside the Cage + /// \param motmed Medium material of the mother volume + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createMFTRailsPair(const TGeoMedium* motmed, const TGeoManager* mgr = gGeoManager); + + /// Creates a hinge holding a pair of MFT rails inside the Cage + /// \param mgr The GeoManager (used only to get the proper material) + TGeoVolume* createMFTRailsHinge(const TGeoManager* mgr = gGeoManager); + // Parameters static const Double_t sCageYInBarrel; ///< Global Y translation @@ -244,6 +258,29 @@ class V3Cage : public V11Geometry static const Double_t sCageCrossBarThick; ///< Closing cross bar thickness static const Double_t sCageCrossBarPhi; ///< Closing cross bar angle + // MFT Rails inside the Cage + static const Double_t sCageMFTRailZLen; ///< Total length of the rail + static const Double_t sCageMFTRailZPos; ///< Rail global Z position + static const Double_t sCageMFTRailTotWidth; ///< Total width of the rail + static const Double_t sCageMFTRailExtWidth; ///< Width of the external part + static const Double_t sCageMFTRailIntWidth; ///< Width of the internal part + static const Double_t sCageMFTRailBaseWidth; ///< Width of the rail base + static const Double_t sCageMFTRailTotHeight; ///< Total height of the rail + static const Double_t sCageMFTRailExtHeight; ///< Height of the external part + static const Double_t sCageMFTRailIntHeight; ///< Height of the internal part + static const Double_t sCageMFTRailsXDist; ///< X distance between rails + + // MFT Rail hinges + static const Double_t sCageMFTHingeTotWid; ///< Total width of a hinge + static const Double_t sCageMFTHingeIntWid; ///< Width of hinge inner part + static const Double_t sCageMFTHingeHeight; ///< Total height of the rail + static const Double_t sCageMFTHingeIntHei; ///< Height of hinge inner part + static const Double_t sCageMFTHingeTotLen; ///< Total length of a hinge + static const Double_t sCageMFTHingeIntLen; ///< Length of hinge inner part + static const Double_t sCageMFTHingeBulgeWid; ///< Width of a hinge bulge + static const Double_t sCageMFTHingeBulgeHei; ///< Height of a hinge bulge + static const Double_t sCageMFTHingeBulgePos; ///< X position of a hinge bulge + ClassDefOverride(V3Cage, 0); // ITS v3 support geometry }; } // namespace its diff --git a/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V3Layer.h b/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V3Layer.h index 15683feac4613..bc4fd6b0dadd4 100644 --- a/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V3Layer.h +++ b/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/V3Layer.h @@ -353,43 +353,49 @@ class V3Layer : public V11Geometry static const Int_t sIBNChipRows; ///< IB chip rows in module static const Double_t sIBChipZGap; ///< Gap between IB chips on Z - static const Double_t sIBModuleZLength; ///< IB Module Length along Z - static const Double_t sIBFPCWiderXPlus; ///< FPC protrusion at X>0 - static const Double_t sIBFPCWiderXNeg; ///< FPC protrusion at X<0 - static const Double_t sIBFlexCableAlThick; ///< Thickness of FPC Aluminum - static const Double_t sIBFPCAlGNDWidth; ///< Width of total FPC Al Gnd - static const Double_t sIBFPCAlAnodeWidth1; ///< Width of FPC Al Anode - static const Double_t sIBFPCAlAnodeWidth2; ///< Width of FPC Al Anode - static const Double_t sIBFlexCableKapThick; ///< Thickness of FPC Kapton - static const Double_t sIBFlexCablePolyThick; ///< Thickness of FPC Coverlay - static const Double_t sIBFlexCapacitorXWid; ///< IB capaictor X width - static const Double_t sIBFlexCapacitorYHi; ///< IB capaictor Y height - static const Double_t sIBFlexCapacitorZLen; ///< IB capaictor Z length - static const Double_t sIBColdPlateWidth; ///< IB cold plate X width - static const Double_t sIBColdPlateZLen; ///< IB cold plate Z length - static const Double_t sIBGlueThick; ///< IB glue thickness - static const Double_t sIBCarbonFleeceThick; ///< IB carbon fleece thickness - static const Double_t sIBCarbonPaperThick; ///< IB Carbon Paper Thickness - static const Double_t sIBCarbonPaperWidth; ///< IB Carbon Paper X Width - static const Double_t sIBCarbonPaperZLen; ///< IB Carbon Paper Z Length - static const Double_t sIBK13D2UThick; ///< IB k13d2u prepreg thickness - static const Double_t sIBCoolPipeInnerD; ///< IB cooling inner diameter - static const Double_t sIBCoolPipeThick; ///< IB cooling pipe thickness - static const Double_t sIBCoolPipeXDist; ///< IB cooling pipe separation - static const Double_t sIBCoolPipeZLen; ///< IB cooling pipe length - static const Double_t sIBTopVertexWidth1; ///< IB TopVertex width - static const Double_t sIBTopVertexWidth2; ///< IB TopVertex width - static const Double_t sIBTopVertexHeight; ///< IB TopVertex height - static const Double_t sIBTopVertexAngle; ///< IB TopVertex aperture angle - static const Double_t sIBSideVertexWidth; ///< IB SideVertex width - static const Double_t sIBSideVertexHeight; ///< IB SideVertex height - static const Double_t sIBTopFilamentSide; ///< IB TopFilament side - static const Double_t sIBTopFilamentAlpha; ///< IB TopFilament angle - static const Double_t sIBTopFilamentInterZ; ///< IB TopFilament Z interdist - static const Double_t sIBEndSupportThick; ///< IB end support thickness - static const Double_t sIBEndSupportZLen; ///< IB end support length - static const Double_t sIBEndSupportXUp; ///< IB end support X up wide - static const Double_t sIBEndSupportOpenPhi; ///< IB end support opening phi + static const Double_t sIBModuleZLength; ///< IB Module Length along Z + static const Double_t sIBFPCWiderXPlus; ///< FPC protrusion at X>0 + static const Double_t sIBFPCWiderXNeg; ///< FPC protrusion at X<0 + static const Double_t sIBFlexCableAlThick; ///< Thickness of FPC Aluminum + static const Double_t sIBFPCAlGNDWidth; ///< Width of total FPC Al Gnd + static const Double_t sIBFPCAlAnodeWidth1; ///< Width of FPC Al Anode + static const Double_t sIBFPCAlAnodeWidth2; ///< Width of FPC Al Anode + static const Double_t sIBFlexCableKapThick; ///< Thickness of FPC Kapton + static const Double_t sIBFlexCablePolyThick; ///< Thickness of FPC Coverlay + static const Double_t sIBFlexCapacitor1XWid; ///< IB small capacitor X width + static const Double_t sIBFlexCapacitor1YHi; ///< IB small capacitor Y height + static const Double_t sIBFlexCapacitor1ZLen; ///< IB small capacitor Z length + static const Double_t sIBFlexCapacitor22XWid; ///< IB large capacitor X width + static const Double_t sIBFlexCapacitor22YHi; ///< IB large capacitor Y height + static const Double_t sIBFlexCapacitor22ZLen; ///< IB large capacitor Z length + static const Double_t sIBFlexResistorXWid; ///< IB FPC resistor X width + static const Double_t sIBFlexResistorYHi; ///< IB FPC resistor Y height + static const Double_t sIBFlexResistorZLen; ///< IB FPC resistor Z length + static const Double_t sIBColdPlateWidth; ///< IB cold plate X width + static const Double_t sIBColdPlateZLen; ///< IB cold plate Z length + static const Double_t sIBGlueThick; ///< IB glue thickness + static const Double_t sIBCarbonFleeceThick; ///< IB carbon fleece thickness + static const Double_t sIBCarbonPaperThick; ///< IB Carbon Paper Thickness + static const Double_t sIBCarbonPaperWidth; ///< IB Carbon Paper X Width + static const Double_t sIBCarbonPaperZLen; ///< IB Carbon Paper Z Length + static const Double_t sIBK13D2UThick; ///< IB k13d2u prepreg thickness + static const Double_t sIBCoolPipeInnerD; ///< IB cooling inner diameter + static const Double_t sIBCoolPipeThick; ///< IB cooling pipe thickness + static const Double_t sIBCoolPipeXDist; ///< IB cooling pipe separation + static const Double_t sIBCoolPipeZLen; ///< IB cooling pipe length + static const Double_t sIBTopVertexWidth1; ///< IB TopVertex width + static const Double_t sIBTopVertexWidth2; ///< IB TopVertex width + static const Double_t sIBTopVertexHeight; ///< IB TopVertex height + static const Double_t sIBTopVertexAngle; ///< IB TopVertex aperture angle + static const Double_t sIBSideVertexWidth; ///< IB SideVertex width + static const Double_t sIBSideVertexHeight; ///< IB SideVertex height + static const Double_t sIBTopFilamentSide; ///< IB TopFilament side + static const Double_t sIBTopFilamentAlpha; ///< IB TopFilament angle + static const Double_t sIBTopFilamentInterZ; ///< IB TopFilament Z interdist + static const Double_t sIBEndSupportThick; ///< IB end support thickness + static const Double_t sIBEndSupportZLen; ///< IB end support length + static const Double_t sIBEndSupportXUp; ///< IB end support X up wide + static const Double_t sIBEndSupportOpenPhi; ///< IB end support opening phi static const Double_t sIBConnectorXWidth; ///< IB Connectors Width static const Double_t sIBConnectorYTot; ///< IB Connectors total height diff --git a/Detectors/ITSMFT/ITS/simulation/src/Detector.cxx b/Detectors/ITSMFT/ITS/simulation/src/Detector.cxx index 2304a9102092a..63d7a8ad8dfa2 100644 --- a/Detectors/ITSMFT/ITS/simulation/src/Detector.cxx +++ b/Detectors/ITSMFT/ITS/simulation/src/Detector.cxx @@ -61,6 +61,7 @@ using Segmentation = o2::itsmft::SegmentationAlpide; using namespace o2::its; #ifdef ENABLE_UPGRADES +#include "ITS3Simulation/DescriptorInnerBarrelITS3.h" using namespace o2::its3; #endif @@ -477,10 +478,11 @@ void Detector::createMaterials() Float_t dInox304 = 7.85; // Ceramic (for IB capacitors) (BaTiO3) + // Density includes soldering 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; + Float_t dCeramic = 8.28; // Rohacell (C9 H13 N1 O2) Float_t aRohac[4] = {12.01, 1.01, 14.010, 16.}; @@ -1105,7 +1107,7 @@ void Detector::addAlignableVolumes() const TString detName = GetName(); TString path = Form("/cave_1/barrel_1/%s_2", GeometryTGeo::getITSVolPattern()); - TString sname = GeometryTGeo::composeSymNameITS((detName == "IT3")); + TString sname = GeometryTGeo::composeSymNameITS(); LOG(debug) << sname << " <-> " << path; @@ -1116,15 +1118,19 @@ void Detector::addAlignableVolumes() const Int_t lastUID = 0; for (Int_t lr = 0; lr < mNumberLayers; lr++) { if (lr < mNumberInnerLayers) { +#ifdef ENABLE_UPGRADES if (detName == "ITS") { ((DescriptorInnerBarrelITS2*)mDescriptorIB.get())->addAlignableVolumesLayer(lr, mWrapperLayerId[lr], path, lastUID); + } else { + ((DescriptorInnerBarrelITS3*)mDescriptorIB.get())->addAlignableVolumesLayer(lr, mWrapperLayerId[lr], path, lastUID); } +#else + ((DescriptorInnerBarrelITS2*)mDescriptorIB.get())->addAlignableVolumesLayer(lr, mWrapperLayerId[lr], path, lastUID); +#endif } else { addAlignableVolumesLayer(lr, path, lastUID); } } - - return; } void Detector::addAlignableVolumesLayer(int lr, TString& parent, Int_t& lastUID) const @@ -1147,8 +1153,6 @@ void Detector::addAlignableVolumesLayer(int lr, TString& parent, Int_t& lastUID) for (Int_t hb = start; hb < nhbarrel; hb++) { addAlignableVolumesHalfBarrel(lr, hb, path, lastUID); } - - return; } void Detector::addAlignableVolumesHalfBarrel(Int_t lr, Int_t hb, TString& parent, Int_t& lastUID) const @@ -1176,8 +1180,6 @@ void Detector::addAlignableVolumesHalfBarrel(Int_t lr, Int_t hb, TString& parent for (int st = 0; st < nstaves; st++) { addAlignableVolumesStave(lr, hb, st, path, lastUID); } - - return; } void Detector::addAlignableVolumesStave(Int_t lr, Int_t hb, Int_t st, TString& parent, Int_t& lastUID) const @@ -1204,8 +1206,6 @@ void Detector::addAlignableVolumesStave(Int_t lr, Int_t hb, Int_t st, TString& p for (Int_t sst = start; sst < nhstave; sst++) { addAlignableVolumesHalfStave(lr, hb, st, sst, path, lastUID); } - - return; } void Detector::addAlignableVolumesHalfStave(Int_t lr, Int_t hb, Int_t st, Int_t hst, TString& parent, Int_t& lastUID) const @@ -1235,8 +1235,6 @@ void Detector::addAlignableVolumesHalfStave(Int_t lr, Int_t hb, Int_t st, Int_t for (Int_t md = start; md < nmodules; md++) { addAlignableVolumesModule(lr, hb, st, hst, md, path, lastUID); } - - return; } void Detector::addAlignableVolumesModule(Int_t lr, Int_t hb, Int_t st, Int_t hst, Int_t md, TString& parent, Int_t& lastUID) const @@ -1265,8 +1263,6 @@ void Detector::addAlignableVolumesModule(Int_t lr, Int_t hb, Int_t st, Int_t hst for (Int_t ic = 0; ic < nchips; ic++) { addAlignableVolumesChip(lr, hb, st, hst, md, ic, path, lastUID); } - - return; } void Detector::addAlignableVolumesChip(Int_t lr, Int_t hb, Int_t st, Int_t hst, Int_t md, Int_t ch, TString& parent, diff --git a/Detectors/ITSMFT/ITS/simulation/src/V3Cage.cxx b/Detectors/ITSMFT/ITS/simulation/src/V3Cage.cxx index 3b17d7afeef3d..bd9ce1cd333a2 100644 --- a/Detectors/ITSMFT/ITS/simulation/src/V3Cage.cxx +++ b/Detectors/ITSMFT/ITS/simulation/src/V3Cage.cxx @@ -167,6 +167,28 @@ const Double_t V3Cage::sCageCrossZLength = 8 * sMm; const Double_t V3Cage::sCageCrossBarThick = 20 * sMm; const Double_t V3Cage::sCageCrossBarPhi = 25; // Deg +// MFT rails inside Cage +const Double_t V3Cage::sCageMFTRailZLen = 1874 * sMm; +const Double_t V3Cage::sCageMFTRailZPos = 6.3 * sMm; +const Double_t V3Cage::sCageMFTRailTotWidth = 27 * sMm; +const Double_t V3Cage::sCageMFTRailExtWidth = 24 * sMm; +const Double_t V3Cage::sCageMFTRailIntWidth = 17.5 * sMm; +const Double_t V3Cage::sCageMFTRailBaseWidth = 22 * sMm; +const Double_t V3Cage::sCageMFTRailTotHeight = 8.9 * sMm; +const Double_t V3Cage::sCageMFTRailExtHeight = 5.9 * sMm; +const Double_t V3Cage::sCageMFTRailIntHeight = 3.5 * sMm; +const Double_t V3Cage::sCageMFTRailsXDist = 44 * sMm; + +const Double_t V3Cage::sCageMFTHingeTotWid = 164 * sMm; +const Double_t V3Cage::sCageMFTHingeIntWid = 141.3 * sMm; +const Double_t V3Cage::sCageMFTHingeHeight = 8 * sMm; +const Double_t V3Cage::sCageMFTHingeIntHei = 6 * sMm; +const Double_t V3Cage::sCageMFTHingeTotLen = 41 * sMm; +const Double_t V3Cage::sCageMFTHingeIntLen = 28 * sMm; +const Double_t V3Cage::sCageMFTHingeBulgeWid = 10 * sMm; +const Double_t V3Cage::sCageMFTHingeBulgeHei = 10 * sMm; +const Double_t V3Cage::sCageMFTHingeBulgePos = 7 * sMm; + ClassImp(V3Cage); V3Cage::V3Cage() @@ -251,6 +273,9 @@ void V3Cage::createAndPlaceCage(TGeoVolume* mother, const TGeoManager* mgr) zpos = sBPSuppZPos + sBPSuppCollarBeamWid / 2; mother->AddNode(cageBPSupport, 1, new TGeoTranslation(0, ypos, zpos)); + // The MFT Rails inside the Cage + createAndPlaceMFTRailsInsideCage(mother, mgr); + return; } @@ -1648,3 +1673,240 @@ TGeoVolume* V3Cage::createCageClosingCross(const TGeoManager* mgr) // Finally return the closing cross volume return closCrossVol; } + +void V3Cage::createAndPlaceMFTRailsInsideCage(TGeoVolume* mother, const TGeoManager* mgr) +{ + // + // Creates the MFT Rails located inside the Cage and place them + // + // Input: + // motmat : the material of the mother volume (for the container box) + // mgr : the GeoManager (used only to get the proper material) + // + // Output: + // + // Return: + // + // Created: 10 May 2025 Mario Sitta + // Updated: 20 May 2025 Mario Sitta Hinges added + // + + // Local variables + Double_t rdist, rpos, xpos, yposup, yposdw, zpos, alpha; + Double_t xbox, ybox; + + // Create a pair of rails (a BBox container is returned) + TGeoVolume* cageMFTRails = createMFTRailsPair(mother->GetMedium(), mgr); + + // Create hinge holding a pair of rails + TGeoVolume* cageMFTRailsHinge = createMFTRailsHinge(mgr); + + // Now compute the radial distance and the XY position of the box + xbox = (static_cast(cageMFTRails->GetShape()))->GetDX(); + ybox = (static_cast(cageMFTRails->GetShape()))->GetDY(); + + rdist = TMath::Sqrt(sCageCoverRint * sCageCoverRint - xbox * xbox); + rpos = rdist - ybox; + + // Finally place the four pairs of rails inside the mother volume + xpos = rpos * TMath::Sin(sCageEndCapCableCutPhi * TMath::DegToRad()); + yposup = rpos * TMath::Cos(sCageEndCapCableCutPhi * TMath::DegToRad()) + sCageYInBarrel; + yposdw = rpos * TMath::Cos(sCageEndCapCableCutPhi * TMath::DegToRad()) - sCageYInBarrel; + zpos = sCageMFTRailZPos; + + alpha = -sCageEndCapCableCutPhi + 180; + mother->AddNode(cageMFTRails, 1, new TGeoCombiTrans(xpos, yposup, zpos, new TGeoRotation("", alpha, 0, 0))); + alpha = sCageEndCapCableCutPhi + 180; + mother->AddNode(cageMFTRails, 2, new TGeoCombiTrans(-xpos, yposup, zpos, new TGeoRotation("", alpha, 0, 0))); + + alpha = sCageEndCapCableCutPhi; + mother->AddNode(cageMFTRails, 3, new TGeoCombiTrans(xpos, -yposdw, zpos, new TGeoRotation("", alpha, 0, 0))); + alpha = -sCageEndCapCableCutPhi; + mother->AddNode(cageMFTRails, 4, new TGeoCombiTrans(-xpos, -yposdw, zpos, new TGeoRotation("", alpha, 0, 0))); + + // And the hinges too + xpos = rdist * TMath::Sin(sCageEndCapCableCutPhi * TMath::DegToRad()); + yposup = rdist * TMath::Cos(sCageEndCapCableCutPhi * TMath::DegToRad()) + sCageYInBarrel; + yposdw = rdist * TMath::Cos(sCageEndCapCableCutPhi * TMath::DegToRad()) - sCageYInBarrel; + zpos = (static_cast(cageMFTRails->GetShape()))->GetDZ() + sCageMFTRailZPos; + + alpha = sCageEndCapCableCutPhi; + mother->AddNode(cageMFTRailsHinge, 1, new TGeoCombiTrans(xpos, yposup, zpos, new TGeoRotation("", -alpha, 0, 0))); + mother->AddNode(cageMFTRailsHinge, 2, new TGeoCombiTrans(-xpos, yposup, zpos, new TGeoRotation("", alpha, 0, 0))); + + mother->AddNode(cageMFTRailsHinge, 3, new TGeoCombiTrans(xpos, -yposdw, zpos, new TGeoRotation("", 180 + alpha, 0, 0))); + mother->AddNode(cageMFTRailsHinge, 4, new TGeoCombiTrans(-xpos, -yposdw, zpos, new TGeoRotation("", 180 - alpha, 0, 0))); + + zpos = (static_cast(cageMFTRails->GetShape()))->GetDZ() - sCageMFTRailZPos; + mother->AddNode(cageMFTRailsHinge, 5, new TGeoCombiTrans(xpos, yposup, -zpos, new TGeoRotation("", 90, 180, -90 + alpha))); // On Z<0 apply 180deg rotation on Y axis + mother->AddNode(cageMFTRailsHinge, 6, new TGeoCombiTrans(-xpos, yposup, -zpos, new TGeoRotation("", 90, 180, -90 - alpha))); + + mother->AddNode(cageMFTRailsHinge, 7, new TGeoCombiTrans(xpos, -yposdw, -zpos, new TGeoRotation("", 90, 180, 90 - alpha))); + mother->AddNode(cageMFTRailsHinge, 8, new TGeoCombiTrans(-xpos, -yposdw, -zpos, new TGeoRotation("", 90, 180, 90 + alpha))); + + return; +} + +TGeoVolume* V3Cage::createMFTRailsPair(const TGeoMedium* motmed, const TGeoManager* mgr) +{ + // + // Creates a pair of MFT Rails located inside the Cage (from drawings + // ALI-MFT-DF-0057 and elements therein) + // A box containing a pair of rails is returned (a physical box + // is preferred over an Assembly for better performance) + // + // Input: + // motmed : the medium of the mother volume (for the container box) + // mgr : the GeoManager (used only to get the proper material) + // + // Output: + // + // Return: + // A rail pair as a TGeoVolume + // + // Created: 10 May 2025 Mario Sitta + // + + // Local variables + const Int_t nv = 16; + Double_t xv[nv], yv[nv]; + Double_t deltah, xlen, ylen, zlen; + Double_t xpos, ypos; + + // The shape of a single rail: a Xtru + xv[0] = sCageMFTRailBaseWidth / 2; + yv[0] = 0.; + xv[1] = xv[0]; + yv[1] = sCageMFTRailTotHeight - sCageMFTRailExtHeight; + xv[2] = sCageMFTRailTotWidth / 2; + yv[2] = yv[1]; + xv[3] = xv[2]; + yv[3] = sCageMFTRailTotHeight; + xv[4] = sCageMFTRailIntWidth / 2; + yv[4] = yv[3]; + deltah = (sCageMFTRailExtHeight - sCageMFTRailIntHeight) / 2; + xv[5] = xv[4]; + yv[5] = yv[4] - deltah; + xv[6] = sCageMFTRailExtWidth / 2; + yv[6] = yv[5]; + xv[7] = xv[6]; + yv[7] = yv[6] - sCageMFTRailIntHeight; + + for (Int_t i = 8; i < nv; i++) { + xv[i] = -xv[15 - i]; + yv[i] = yv[15 - i]; + } + + zlen = sCageMFTRailZLen / 2; + + TGeoXtru* mftRailSh = new TGeoXtru(2); + mftRailSh->SetName("mftrailshape"); + mftRailSh->DefinePolygon(nv, xv, yv); + mftRailSh->DefineSection(0, -zlen); + mftRailSh->DefineSection(1, zlen); + + // The air container: a BBox + xlen = 2 * sCageMFTRailTotWidth + sCageMFTRailsXDist; + ylen = sCageMFTRailTotHeight / 2; + zlen = sCageMFTRailZLen / 2; + TGeoBBox* mftRailBoxSh = new TGeoBBox(xlen / 2, ylen, zlen); + + // We have the shape: now create the real volume + TGeoMedium* medAl = mgr->GetMedium(Form("%s_ALUMINUM$", GetDetName())); + + TGeoVolume* mftRailVol = new TGeoVolume("MFTRailInsideCage", mftRailSh, medAl); + mftRailVol->SetFillColor(kGray); + mftRailVol->SetLineColor(kGray); + + TGeoVolume* mftRailBoxVol = new TGeoVolume("MFTRailPairInsideCage", mftRailBoxSh, motmed); + + // Put the two rails inside the holding box + // (rail Y origin is on its lower face) + xpos = mftRailBoxSh->GetDX() - 0.5 * sCageMFTRailTotWidth; + ypos = mftRailBoxSh->GetDY(); + mftRailBoxVol->AddNode(mftRailVol, 1, new TGeoTranslation(xpos, -ypos, 0)); + mftRailBoxVol->AddNode(mftRailVol, 2, new TGeoTranslation(-xpos, -ypos, 0)); + + // Finally return the rails volume + return mftRailBoxVol; +} + +TGeoVolume* V3Cage::createMFTRailsHinge(const TGeoManager* mgr) +{ + // + // Creates a hinge holding a pair of MFT Rails to the Cage (from drawing + // ALIMFT-0042 and elements inside CAD files) + // + // Input: + // mgr : the GeoManager (used only to get the proper material) + // + // Output: + // + // Return: + // A rail hinge as a TGeoVolume + // + // Created: 19 May 2025 Mario Sitta + // + + // Local variables + const Int_t nv = 6; + Double_t xv[nv], yv[nv]; + Double_t xlen, ylen, zlen; + Double_t xpos, ypos, zpos; + + TString compoShape; + + // The main body: a Xtru + xv[0] = sCageMFTHingeTotWid / 2; + yv[0] = 0; + xv[1] = xv[0]; + yv[1] = sCageMFTHingeIntHei; + xv[2] = sCageMFTHingeIntWid / 2; + yv[2] = sCageMFTHingeHeight; + + for (Int_t i = 3; i < nv; i++) { + xv[i] = -xv[5 - i]; + yv[i] = yv[5 - i]; + } + + zlen = sCageMFTHingeIntLen / 2; + + TGeoXtru* mftHingeBodySh = new TGeoXtru(2); + mftHingeBodySh->SetName("mfthingebodyshape"); + mftHingeBodySh->DefinePolygon(nv, xv, yv); + mftHingeBodySh->DefineSection(0, -zlen); + mftHingeBodySh->DefineSection(1, zlen); + + // The bulge: a BBox + xlen = sCageMFTHingeBulgeWid / 2; + ylen = sCageMFTHingeBulgeHei / 2; + zlen = (sCageMFTHingeTotLen - sCageMFTHingeIntLen) / 2; + TGeoBBox* mftHingeBulgeSh = new TGeoBBox("mfthingebulgeshape", xlen, ylen, zlen); + + // The actual hinge: a CompositeShape + xpos = mftHingeBodySh->GetX(0) - (sCageMFTHingeBulgePos + mftHingeBulgeSh->GetDX()); + ypos = mftHingeBodySh->GetY(2) - mftHingeBulgeSh->GetDY(); + zpos = mftHingeBodySh->GetZ(1) + mftHingeBulgeSh->GetDZ(); + + TGeoTranslation* bulgpos1 = new TGeoTranslation(xpos, ypos, zpos); + bulgpos1->SetName("bulge1pos"); + bulgpos1->RegisterYourself(); + + TGeoTranslation* bulgpos2 = new TGeoTranslation(-xpos, ypos, zpos); + bulgpos2->SetName("bulge2pos"); + bulgpos2->RegisterYourself(); + + compoShape = Form("mfthingebodyshape+mfthingebulgeshape:bulge1pos+mfthingebulgeshape:bulge2pos"); + + TGeoCompositeShape* mftRailHingeSh = new TGeoCompositeShape(compoShape); + + // We have the shape: now create the real volume + TGeoMedium* medAl = mgr->GetMedium(Form("%s_ALUMINUM$", GetDetName())); + + TGeoVolume* mftRailHingeVol = new TGeoVolume("MFTRailHingeInsideCage", mftRailHingeSh, medAl); + mftRailHingeVol->SetFillColor(kGreen); + mftRailHingeVol->SetLineColor(kGreen); + + // Finally return the hinge volume + return mftRailHingeVol; +} diff --git a/Detectors/ITSMFT/ITS/simulation/src/V3Layer.cxx b/Detectors/ITSMFT/ITS/simulation/src/V3Layer.cxx index 33a1bedec74eb..e930aa23de030 100644 --- a/Detectors/ITSMFT/ITS/simulation/src/V3Layer.cxx +++ b/Detectors/ITSMFT/ITS/simulation/src/V3Layer.cxx @@ -61,9 +61,15 @@ const Double_t V3Layer::sIBFPCAlAnodeWidth1 = 13.0 * sMm; const Double_t V3Layer::sIBFPCAlAnodeWidth2 = 14.7 * sMm; const Double_t V3Layer::sIBFlexCableKapThick = 75.0 * sMicron; const Double_t V3Layer::sIBFlexCablePolyThick = 20.0 * sMicron; -const Double_t V3Layer::sIBFlexCapacitorXWid = 0.2 * sMm; -const Double_t V3Layer::sIBFlexCapacitorYHi = 0.2 * sMm; -const Double_t V3Layer::sIBFlexCapacitorZLen = 0.4 * sMm; +const Double_t V3Layer::sIBFlexCapacitor1XWid = 0.5 * sMm; +const Double_t V3Layer::sIBFlexCapacitor1YHi = 0.5 * sMm; +const Double_t V3Layer::sIBFlexCapacitor1ZLen = 1.0 * sMm; +const Double_t V3Layer::sIBFlexCapacitor22XWid = 0.7 * sMm; +const Double_t V3Layer::sIBFlexCapacitor22YHi = 0.6 * sMm; +const Double_t V3Layer::sIBFlexCapacitor22ZLen = 1.1 * sMm; +const Double_t V3Layer::sIBFlexResistorXWid = 0.2 * sMm; +const Double_t V3Layer::sIBFlexResistorYHi = 0.2 * sMm; +const Double_t V3Layer::sIBFlexResistorZLen = 0.4 * sMm; const Double_t V3Layer::sIBColdPlateWidth = 15.4 * sMm; const Double_t V3Layer::sIBColdPlateZLen = 290.0 * sMm; const Double_t V3Layer::sIBGlueThick = 50.0 * sMicron; @@ -599,8 +605,11 @@ TGeoVolume* V3Layer::createModuleInnerB(const Double_t xchip, const Double_t zch // the module as a TGeoVolume // // Updated: 03 Apr 2021 + // Updated: 03 Nov 2025 Change volume from BBox to Xtru to avoid fake overlaps Double_t xtot, ytot, ztot; + Double_t ymid, shrinkFactor = 0.73; + Double_t xv[5], yv[5]; Double_t xpos, ypos, zpos; const Int_t nameLen = 30; char volumeName[nameLen]; @@ -619,9 +628,25 @@ TGeoVolume* V3Layer::createModuleInnerB(const Double_t xchip, const Double_t zch Double_t ygnd = (static_cast(aluGndCableVol->GetShape()))->GetDY(); Double_t yano = (static_cast(aluAnodeCableVol->GetShape()))->GetDY(); - ytot = sIBGlueThick / 2 + ygnd + sIBFlexCableKapThick / 2 + yano + sIBFlexCapacitorYHi / 2; + ytot = sIBGlueThick / 2 + ygnd + sIBFlexCableKapThick / 2 + yano + sIBFlexCapacitor22YHi / 2; + ymid = sIBGlueThick / 2 + ygnd + sIBFlexCableKapThick / 2 + yano; - TGeoBBox* module = new TGeoBBox(xtot, ytot, ztot); + xv[0] = xtot; + yv[0] = -ytot; + xv[1] = xv[0]; + yv[1] = yv[0] + 6 * ymid; + xv[2] = xtot * shrinkFactor; + yv[2] = ytot; + xv[3] = -xtot; + yv[3] = yv[2]; + xv[4] = xv[3]; + yv[4] = yv[0]; + + TGeoXtru* module = new TGeoXtru(2); + module->DefinePolygon(6, xv, yv); + module->DefinePolygon(5, xv, yv); + module->DefineSection(0, -ztot); + module->DefineSection(1, ztot); // Now the volumes TGeoMedium* medAir = mgr->GetMedium(Form("%s_AIR$", GetDetName())); @@ -674,6 +699,7 @@ void V3Layer::createIBCapacitors(TGeoVolume* modvol, Double_t zchip, Double_t yz // // Created: 13 Feb 2018 Mario Sitta // Updated: 03 Apr 2019 Mario Sitta Fix positions (180' rotation) + // Updated: 31 Oct 2025 Mario Sitta Fix dimensions and weight // // Position of the various capacitors (A.Junique private communication @@ -705,63 +731,72 @@ void V3Layer::createIBCapacitors(TGeoVolume* modvol, Double_t zchip, Double_t yz Double_t xpos, ypos, zpos; Int_t nCapacitors; - TGeoVolume *capacitor, *resistor; + TGeoVolume *capacitorSmall, *capacitorLarge, *resistor; - // Check whether we already have the volume, otherwise create it - // (so as to avoid creating multiple copies of the very same volume + // Check whether we already have the volumes, otherwise create them + // (so as to avoid creating multiple copies of the very same volumes // for each layer) - capacitor = mgr->GetVolume("IBFPCCapacitor"); + // The "small" capacitor is the 1 uF substrate capacitor + // The "large" capacitor is the 22 uF analog/digital PS capacitor + capacitorSmall = mgr->GetVolume("IBFPCCapacitorSmall"); - if (!capacitor) { - TGeoBBox* capsh = new TGeoBBox(sIBFlexCapacitorXWid / 2, sIBFlexCapacitorYHi / 2, sIBFlexCapacitorZLen / 2); + if (!capacitorSmall) { + TGeoBBox* capSmsh = new TGeoBBox(sIBFlexCapacitor1XWid / 2, sIBFlexCapacitor1YHi / 2, sIBFlexCapacitor1ZLen / 2); + TGeoBBox* capLgsh = new TGeoBBox(sIBFlexCapacitor22XWid / 2, sIBFlexCapacitor22YHi / 2, sIBFlexCapacitor22ZLen / 2); TGeoMedium* medCeramic = mgr->GetMedium(Form("%s_CERAMIC$", GetDetName())); - capacitor = new TGeoVolume("IBFPCCapacitor", capsh, medCeramic); - capacitor->SetLineColor(kBlack); - capacitor->SetFillColor(kBlack); + capacitorSmall = new TGeoVolume("IBFPCCapacitorSmall", capSmsh, medCeramic); + capacitorSmall->SetLineColor(kBlack); + capacitorSmall->SetFillColor(kBlack); + + capacitorLarge = new TGeoVolume("IBFPCCapacitorLarge", capLgsh, medCeramic); + capacitorLarge->SetLineColor(kBlack); + capacitorLarge->SetFillColor(kBlack); - TGeoBBox* ressh = new TGeoBBox(sIBFlexCapacitorXWid / 2, // Resistors have - sIBFlexCapacitorYHi / 2, // the same dim's - sIBFlexCapacitorZLen / 2); // as capacitors + TGeoBBox* ressh = new TGeoBBox(sIBFlexResistorXWid / 2, + sIBFlexResistorYHi / 2, + sIBFlexResistorZLen / 2); resistor = new TGeoVolume("IBFPCResistor", ressh, medCeramic); resistor->SetLineColor(kBlack); resistor->SetFillColor(kBlack); } else { // Volumes already defined, get them + capacitorLarge = mgr->GetVolume("IBFPCCapacitorLarge"); resistor = mgr->GetVolume("IBFPCResistor"); } // Place all the capacitors (they are really a lot...) - ypos = yzero + sIBFlexCapacitorYHi / 2; + ypos = yzero + sIBFlexCapacitor22YHi / 2; xpos = xGroup1A; for (Int_t j = 0; j < sIBChipsPerRow; j++) { zpos = -mIBModuleZLength / 2 + j * (2 * zchip + sIBChipZGap) + zchip + zGroup1A[0]; - modvol->AddNode(capacitor, 2 * j + 1, new TGeoTranslation(-xpos, ypos, -zpos)); + modvol->AddNode(capacitorLarge, 2 * j + 1, new TGeoTranslation(-xpos, ypos, -zpos)); zpos = -mIBModuleZLength / 2 + j * (2 * zchip + sIBChipZGap) + zchip + zGroup1A[1]; - modvol->AddNode(capacitor, 2 * j + 2, new TGeoTranslation(-xpos, ypos, -zpos)); + modvol->AddNode(capacitorLarge, 2 * j + 2, new TGeoTranslation(-xpos, ypos, -zpos)); } nCapacitors = 2 * sIBChipsPerRow; xpos = xGroup1B; for (Int_t j = 0; j < sIBChipsPerRow; j++) { zpos = -mIBModuleZLength / 2 + j * (2 * zchip + sIBChipZGap) + zchip + zGroup1B; - modvol->AddNode(capacitor, j + 1 + nCapacitors, new TGeoTranslation(-xpos, ypos, -zpos)); + modvol->AddNode(capacitorLarge, j + 1 + nCapacitors, new TGeoTranslation(-xpos, ypos, -zpos)); } nCapacitors += sIBChipsPerRow; + ypos = yzero + sIBFlexCapacitor1YHi / 2; xpos = xGroup2; // We have only 8 in these group, missing the central one for (Int_t j = 0; j < sIBChipsPerRow - 1; j++) { zpos = -mIBModuleZLength / 2 + j * (2 * zchip + sIBChipZGap) + zchip + zGroup2; - modvol->AddNode(capacitor, j + 1 + nCapacitors, new TGeoTranslation(-xpos, ypos, -zpos)); + modvol->AddNode(capacitorSmall, j + 1 + nCapacitors, new TGeoTranslation(-xpos, ypos, -zpos)); } nCapacitors += (sIBChipsPerRow - 1); xpos = xGroup3; zpos = zGroup3; - modvol->AddNode(capacitor, 1 + nCapacitors, new TGeoTranslation(-xpos, ypos, -zpos)); + modvol->AddNode(capacitorSmall, 1 + nCapacitors, new TGeoTranslation(-xpos, ypos, -zpos)); nCapacitors++; for (Int_t j = 0; j < sIBChipsPerRow; j++) { @@ -771,10 +806,11 @@ void V3Layer::createIBCapacitors(TGeoVolume* modvol, Double_t zchip, Double_t yz xpos = xGroup4[0]; } zpos = -mIBModuleZLength / 2 + j * (2 * zchip + sIBChipZGap) + zchip + zGroup4[j]; - modvol->AddNode(capacitor, j + 1 + nCapacitors, new TGeoTranslation(-xpos, ypos, -zpos)); + modvol->AddNode(capacitorSmall, j + 1 + nCapacitors, new TGeoTranslation(-xpos, ypos, -zpos)); } nCapacitors += sIBChipsPerRow; + ypos = yzero + sIBFlexCapacitor22YHi / 2; for (Int_t j = 0; j < nGroup5A; j++) { if (j == 0) { xpos = xGroup5A[0]; @@ -782,14 +818,14 @@ void V3Layer::createIBCapacitors(TGeoVolume* modvol, Double_t zchip, Double_t yz xpos = xGroup5A[1]; } zpos = zGroup5A[j]; - modvol->AddNode(capacitor, j + 1 + nCapacitors, new TGeoTranslation(-xpos, ypos, -zpos)); + modvol->AddNode(capacitorLarge, j + 1 + nCapacitors, new TGeoTranslation(-xpos, ypos, -zpos)); } nCapacitors += nGroup5A; xpos = xGroup5B; for (Int_t j = 0; j < nGroup5B; j++) { zpos = zGroup5B[j]; - modvol->AddNode(capacitor, j + 1 + nCapacitors, new TGeoTranslation(-xpos, ypos, -zpos)); + modvol->AddNode(capacitorLarge, j + 1 + nCapacitors, new TGeoTranslation(-xpos, ypos, -zpos)); } // Place the resistors @@ -1061,7 +1097,7 @@ TGeoVolume* V3Layer::createStaveModelInnerB4(const TGeoManager* mgr) yv[1] = layerHeight + sIBSideVertexHeight + topfil->GetDZ(); ; xv[2] = sIBEndSupportXUp / 2; - yv[2] = sIBStaveHeight + sIBTopFilamentSide / sinD(-theta); // theta is neg + yv[2] = sIBStaveHeight + sIBTopFilamentSide / sinD(-theta) - 0.01; // theta is neg for (Int_t i = 0; i < 3; i++) { xv[3 + i] = -xv[2 - i]; yv[3 + i] = yv[2 - i]; diff --git a/Detectors/ITSMFT/ITS/tracking/CMakeLists.txt b/Detectors/ITSMFT/ITS/tracking/CMakeLists.txt index f8c71e27d0058..1dd64b6f1874b 100644 --- a/Detectors/ITSMFT/ITS/tracking/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/tracking/CMakeLists.txt @@ -14,18 +14,16 @@ o2_add_library(ITStracking SOURCES src/ClusterLines.cxx src/Cluster.cxx src/Configuration.cxx - src/ROframe.cxx + src/FastMultEstConfig.cxx + src/FastMultEst.cxx + src/LineVertexerHelpers.cxx src/TimeFrame.cxx src/IOUtils.cxx - src/Label.cxx - src/Road.cxx src/Tracker.cxx src/TrackerTraits.cxx src/TrackingConfigParam.cxx - src/ClusterLines.cxx src/Vertexer.cxx src/VertexerTraits.cxx - src/Smoother.cxx PUBLIC_LINK_LIBRARIES O2::GPUCommon Microsoft.GSL::GSL @@ -33,14 +31,14 @@ o2_add_library(ITStracking O2::DataFormatsITSMFT O2::SimulationDataFormat O2::ITSBase + O2::CommonUtils O2::ITSReconstruction O2::ITSMFTReconstruction - O2::DataFormatsITS) - -if (OpenMP_CXX_FOUND) - target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) - target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) -endif() + O2::DataFormatsITS + PRIVATE_LINK_LIBRARIES + O2::Steer + TBB::tbb) +# target_compile_options(${targetName} PRIVATE -O0 -g -fPIC -fno-omit-frame-pointer) o2_add_library(ITSTrackingInterface TARGETVARNAME targetName @@ -50,18 +48,17 @@ o2_add_library(ITSTrackingInterface O2::Framework O2::GPUTracking) -if (OpenMP_CXX_FOUND) - target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) - target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) -endif() - o2_target_root_dictionary(ITStracking HEADERS include/ITStracking/ClusterLines.h include/ITStracking/Tracklet.h include/ITStracking/Cluster.h + include/ITStracking/Definitions.h + include/ITStracking/FastMultEstConfig.h include/ITStracking/TrackingConfigParam.h LINKDEF src/TrackingLinkDef.h) if(CUDA_ENABLED OR HIP_ENABLED) add_subdirectory(GPU) endif() + +add_subdirectory(test) diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/ClusterLinesGPU.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/ClusterLinesGPU.h deleted file mode 100644 index 75d75e0f67700..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/ClusterLinesGPU.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file ClusterLinesGPU.h -/// \brief GPU-compliant version of ClusterLines, for the moment separated, might create a common traits for ClusterLines + later specifications for each arch, later. - -#ifndef ITSTRACKINGGPU_CLUSTERLINESGPU_H_ -#define ITSTRACKINGGPU_CLUSTERLINESGPU_H_ - -#include "GPUCommonDef.h" -#include /// Required to properly compile MathUtils -#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; - int timeStamp; - unsigned char realVertex; -}; - -class ClusterLinesGPU final -{ - public: - GPUd() ClusterLinesGPU(const Line& firstLine, const Line& secondLine); // poor man solution to calculate duplets' centroid - GPUd() void computeClusterCentroid(); - GPUdi() float* getVertex() { return mVertex; } - - private: - float mAMatrix[6]; // AX=B - float mBMatrix[3]; // AX=B - float mVertexCandidate[3]; // vertex candidate - float mWeightMatrix[9]; // weight matrix - float mVertex[3]; // cluster centroid position -}; - -} // namespace gpu -} // namespace its -} // namespace o2 -#endif \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameChunk.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameChunk.h deleted file mode 100644 index 4a028bf12eb40..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameChunk.h +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// - -#ifndef TRACKINGITSGPU_INCLUDE_TIMEFRAMECHUNKGPU_H -#define TRACKINGITSGPU_INCLUDE_TIMEFRAMECHUNKGPU_H - -#include "ITStracking/Configuration.h" -#include "ITStracking/TimeFrame.h" - -#include "ITStrackingGPU/ClusterLinesGPU.h" -#include "ITStrackingGPU/Stream.h" - -#include - -namespace o2::its::gpu -{ -template -struct StaticTrackingParameters { - StaticTrackingParameters& operator=(const StaticTrackingParameters& t) = default; - void set(const TrackingParameters& pars) - { - ClusterSharing = pars.ClusterSharing; - MinTrackLength = pars.MinTrackLength; - NSigmaCut = pars.NSigmaCut; - PVres = pars.PVres; - DeltaROF = pars.DeltaROF; - ZBins = pars.ZBins; - PhiBins = pars.PhiBins; - CellDeltaTanLambdaSigma = pars.CellDeltaTanLambdaSigma; - } - - /// General parameters - int ClusterSharing = 0; - int MinTrackLength = nLayers; - float NSigmaCut = 5; - float PVres = 1.e-2f; - int DeltaROF = 0; - int ZBins{256}; - int PhiBins{128}; - - /// Cell finding cuts - float CellDeltaTanLambdaSigma = 0.007f; -}; - -template -class GpuTimeFrameChunk -{ - public: - static size_t computeScalingSizeBytes(const int, const TimeFrameGPUParameters&); - static size_t computeFixedSizeBytes(const TimeFrameGPUParameters&); - static size_t computeRofPerChunk(const TimeFrameGPUParameters&, const size_t); - - GpuTimeFrameChunk() = delete; - GpuTimeFrameChunk(o2::its::TimeFrame* tf, TimeFrameGPUParameters& conf) - { - mTimeFramePtr = tf; - mTFGPUParams = &conf; - } - ~GpuTimeFrameChunk(); - - /// Most relevant operations - void allocate(const size_t, Stream&); - void reset(const Task, Stream&); - size_t loadDataOnDevice(const size_t, const size_t, const int, Stream&); - - /// Interface - Cluster* getDeviceClusters(const int); - int* getDeviceClusterExternalIndices(const int); - int* getDeviceIndexTables(const int); - Tracklet* getDeviceTracklets(const int); - int* getDeviceTrackletsLookupTables(const int); - CellSeed* getDeviceCells(const int); - int* getDeviceCellsLookupTables(const int); - int* getDeviceRoadsLookupTables(const int); - TimeFrameGPUParameters* getTimeFrameGPUParameters() const { return mTFGPUParams; } - - int* getDeviceCUBTmpBuffer() { return mCUBTmpBufferDevice; } - int* getDeviceFoundTracklets() { return mFoundTrackletsDevice; } - int* getDeviceNFoundCells() { return mNFoundCellsDevice; } - int* getDeviceCellNeigboursLookupTables(const int); - int* getDeviceCellNeighbours(const int); - CellSeed** getDeviceArrayCells() const { return mCellsDeviceArray; } - int** getDeviceArrayNeighboursCell() const { return mNeighboursCellDeviceArray; } - int** getDeviceArrayNeighboursCellLUT() const { return mNeighboursCellLookupTablesDeviceArray; } - - /// Vertexer only - int* getDeviceNTrackletCluster(const int combid) { return mNTrackletsPerClusterDevice[combid]; } - Line* getDeviceLines() { return mLinesDevice; }; - int* getDeviceNFoundLines() { return mNFoundLinesDevice; } - int* getDeviceNExclusiveFoundLines() { return mNExclusiveFoundLinesDevice; } - unsigned char* getDeviceUsedTracklets() { return mUsedTrackletsDevice; } - int* getDeviceClusteredLines() { return mClusteredLinesDevice; } - size_t getNPopulatedRof() const { return mNPopulatedRof; } - - private: - /// Host - std::array, nLayers> mHostClusters; - std::array, nLayers> mHostIndexTables; - - /// Device - std::array mClustersDevice; - std::array mClusterExternalIndicesDevice; - std::array mIndexTablesDevice; - std::array mTrackletsDevice; - std::array mTrackletsLookupTablesDevice; - std::array mCellsDevice; - // Road* mRoadsDevice; - std::array mCellsLookupTablesDevice; - std::array mNeighboursCellDevice; - std::array mNeighboursCellLookupTablesDevice; - std::array mRoadsLookupTablesDevice; - - // These are to make them accessible using layer index - CellSeed** mCellsDeviceArray; - int** mNeighboursCellDeviceArray; - int** mNeighboursCellLookupTablesDeviceArray; - - // Small accessory buffers - int* mCUBTmpBufferDevice; - int* mFoundTrackletsDevice; - int* mNFoundCellsDevice; - - /// Vertexer only - Line* mLinesDevice; - int* mNFoundLinesDevice; - int* mNExclusiveFoundLinesDevice; - unsigned char* mUsedTrackletsDevice; - std::array mNTrackletsPerClusterDevice; - int* mClusteredLinesDevice; - - /// State and configuration - bool mAllocated = false; - size_t mNRof = 0; - size_t mNPopulatedRof = 0; - o2::its::TimeFrame* mTimeFramePtr = nullptr; - TimeFrameGPUParameters* mTFGPUParams = nullptr; -}; -} // namespace o2::its::gpu -#endif \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameGPU.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameGPU.h index 88666cdfdb7fb..5f56e3f272473 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameGPU.h +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameGPU.h @@ -13,214 +13,258 @@ #ifndef TRACKINGITSGPU_INCLUDE_TIMEFRAMEGPU_H #define TRACKINGITSGPU_INCLUDE_TIMEFRAMEGPU_H +#include +#include + +#include "ITStracking/BoundedAllocator.h" #include "ITStracking/TimeFrame.h" #include "ITStracking/Configuration.h" #include "ITStrackingGPU/Utils.h" -#include - namespace o2::its::gpu { -class Stream; - -class DefaultGPUAllocator : public ExternalAllocator +template +class TimeFrameGPU : public TimeFrame { - void* allocate(size_t size) override; -}; + using typename TimeFrame::IndexTableUtilsN; + using typename TimeFrame::ROFOverlapTableN; + using typename TimeFrame::ROFVertexLookupTableN; + using typename TimeFrame::ROFMaskTableN; + using typename TimeFrame::TrackingTopologyN; + using typename TimeFrame::TrackSeedN; + static constexpr int MaxTransitions = TrackingTopologyN::MaxTransitions; + static constexpr int MaxCells = TrackingTopologyN::MaxCells; + static constexpr int MaxStreams = MaxCells > NLayers ? MaxCells : NLayers; -template -class TimeFrameGPU : public TimeFrame -{ public: - TimeFrameGPU(); - ~TimeFrameGPU(); + TimeFrameGPU() = default; + ~TimeFrameGPU() override = default; /// Most relevant operations + void pushMemoryStack(const int); + void popMemoryStack(const int); void registerHostMemory(const int); void unregisterHostMemory(const int); - void initialise(const int, const TrackingParameters&, const int, IndexTableUtils* utils = nullptr, const TimeFrameGPUParameters* pars = nullptr); - void initDevice(IndexTableUtils*, const TrackingParameters& trkParam, const TimeFrameGPUParameters&, const int, const int); - void initDeviceSAFitting(); - void loadIndexTableUtils(const int); + void initialise(const TrackingParameters&, int maxLayers); + void initialise(const TrackingParameters&, int maxLayers, int iteration); + void loadIndexTableUtils(); + void loadTrackingTopologies(); void loadTrackingFrameInfoDevice(const int); + void createTrackingFrameInfoDeviceArray(); void loadUnsortedClustersDevice(const int); + void createUnsortedClustersDeviceArray(const int = NLayers); void loadClustersDevice(const int); - void loadClustersIndexTables(const int iteration); + void createClustersDeviceArray(const int = NLayers); + void loadClustersIndexTables(const int); + void createClustersIndexTablesArray(); void createUsedClustersDevice(const int); + void createUsedClustersDeviceArray(const int = NLayers); void loadUsedClustersDevice(); - void loadROframeClustersDevice(const int); - void loadMultiplicityCutMask(const int); - void loadVertices(const int); + void loadROFrameClustersDevice(const int); + void createROFrameClustersDeviceArray(); + void loadROFCutMask(const int); + void loadVertices(); + void loadROFOverlapTable(); + void loadROFVertexLookupTable(); + void updateROFVertexLookupTable(); /// - void createTrackletsLUTDevice(const int); + void createTrackletsLUTDevice(bool, const int); + void createTrackletsLUTDeviceArray(); void loadTrackletsDevice(); void loadTrackletsLUTDevice(); void loadCellsDevice(); void loadCellsLUTDevice(); void loadTrackSeedsDevice(); void loadTrackSeedsChi2Device(); - void loadRoadsDevice(); - void loadTrackSeedsDevice(std::vector&); - void createTrackletsBuffers(); + void loadTrackSeedsDevice(bounded_vector&); + void createTrackletsBuffers(const int); + void createTrackletsBuffersArray(); void createCellsBuffers(const int); + void createCellsBuffersArray(); void createCellsDevice(); - void createCellsLUTDevice(); - void createNeighboursIndexTablesDevice(); - void createNeighboursDevice(const unsigned int layer, const unsigned int nNeighbours); - void createNeighboursDevice(const unsigned int layer, std::vector>& neighbours); + void createCellsLUTDevice(const int); + void createCellsLUTDeviceArray(); + void createNeighboursIndexTablesDevice(const int); + void createNeighboursDevice(const unsigned int layer); void createNeighboursLUTDevice(const int, const unsigned int); - void createNeighboursDeviceArray(); - void createTrackITSExtDevice(std::vector&); - void downloadTrackITSExtDevice(std::vector&); - void downloadCellsNeighboursDevice(std::vector>>&, const int); - void downloadNeighboursLUTDevice(std::vector&, const int); + void createTrackITSExtDevice(const size_t); + void downloadTrackITSExtDevice(); + void downloadCellsNeighboursDevice(std::vector>&, const int); + void downloadNeighboursLUTDevice(bounded_vector&, const int); void downloadCellsDevice(); void downloadCellsLUTDevice(); - void unregisterRest(); - template - Stream& getStream(const size_t stream) - { - return *mGpuStreams[stream]; - } - void wipe(const int); + + /// synchronization + auto& getStream(const size_t stream) { return mGpuStreams[stream]; } + auto& getStreams() { return mGpuStreams; } + void syncStream(const size_t stream); + void syncStreams(const bool = true); + void waitEvent(const int, const int); + void recordEvent(const int); + void recordEvents(const int = 0, const int = NLayers); + + /// cleanup + virtual void wipe() final; /// interface - int getNClustersInRofSpan(const int, const int, const int) const; - IndexTableUtils* getDeviceIndexTableUtils() { return mIndexTableUtilsDevice; } + virtual bool isGPU() const noexcept final { return true; } + virtual const char* getName() const noexcept override final { return "GPU"; } + IndexTableUtilsN* getDeviceIndexTableUtils() { return mIndexTableUtilsDevice; } + const auto getDeviceROFOverlapTableView() { return mDeviceROFOverlapTableView; } + const auto getDeviceROFVertexLookupTableView() { return mDeviceROFVertexLookupTableView; } + const auto getDeviceROFMaskTableView() { return mDeviceROFMaskTableView; } + const auto getDeviceTrackingTopologyView() const { return mDeviceTrackingTopologyView; } int* getDeviceROFramesClusters(const int layer) { return mROFramesClustersDevice[layer]; } - std::vector& getTrackITSExt() { return mTrackITSExt; } + auto& getTrackITSExt() { return mTrackITSExt; } Vertex* getDeviceVertices() { return mPrimaryVerticesDevice; } int* getDeviceROFramesPV() { return mROFramesPVDevice; } unsigned char* getDeviceUsedClusters(const int); const o2::base::Propagator* getChainPropagator(); // Hybrid - Road* getDeviceRoads() { return mRoadsDevice; } TrackITSExt* getDeviceTrackITSExt() { return mTrackITSExtDevice; } int* getDeviceNeighboursLUT(const int layer) { return mNeighboursLUTDevice[layer]; } gsl::span getDeviceNeighboursLUTs() { return mNeighboursLUTDevice; } - gpuPair* getDeviceNeighbourPairs(const int layer) { return mNeighbourPairsDevice[layer]; } - std::array& getDeviceNeighboursAll() { return mNeighboursDevice; } - int* getDeviceNeighbours(const int layer) { return mNeighboursDevice[layer]; } - int** getDeviceNeighboursArray() { return mNeighboursDeviceArray; } + CellNeighbour** getDeviceArrayNeighbours() { return mNeighboursDeviceArray; } + std::array& getDeviceNeighboursAll() { return mNeighboursDevice; } + CellNeighbour* getDeviceNeighbours(const int layer) { return mNeighboursDevice[layer]; } TrackingFrameInfo* getDeviceTrackingFrameInfo(const int); const TrackingFrameInfo** getDeviceArrayTrackingFrameInfo() const { return mTrackingFrameInfoDeviceArray; } const Cluster** getDeviceArrayClusters() const { return mClustersDeviceArray; } const Cluster** getDeviceArrayUnsortedClusters() const { return mUnsortedClustersDeviceArray; } const int** getDeviceArrayClustersIndexTables() const { return mClustersIndexTablesDeviceArray; } std::vector getClusterSizes(); - const unsigned char** getDeviceArrayUsedClusters() const { return mUsedClustersDeviceArray; } - const int** getDeviceROframeClusters() const { return mROFrameClustersDeviceArray; } + uint8_t** getDeviceArrayUsedClusters() const { return mUsedClustersDeviceArray; } + const int** getDeviceROFrameClusters() const { return mROFramesClustersDeviceArray; } Tracklet** getDeviceArrayTracklets() { return mTrackletsDeviceArray; } int** getDeviceArrayTrackletsLUT() const { return mTrackletsLUTDeviceArray; } int** getDeviceArrayCellsLUT() const { return mCellsLUTDeviceArray; } int** getDeviceArrayNeighboursCellLUT() const { return mNeighboursCellLUTDeviceArray; } - CellSeed** getDeviceArrayCells() const { return mCellsDeviceArray; } - CellSeed* getDeviceTrackSeeds() { return mTrackSeedsDevice; } + CellSeed** getDeviceArrayCells() { return mCellsDeviceArray; } + TrackSeedN* getDeviceTrackSeeds() { return mTrackSeedsDevice; } + int* getDeviceTrackSeedsLUT() { return mTrackSeedsLUTDevice; } + auto getNTrackSeeds() const { return mNTracks; } o2::track::TrackParCovF** getDeviceArrayTrackSeeds() { return mCellSeedsDeviceArray; } float** getDeviceArrayTrackSeedsChi2() { return mCellSeedsChi2DeviceArray; } int* getDeviceNeighboursIndexTables(const int layer) { return mNeighboursIndexTablesDevice[layer]; } - uint8_t* getDeviceMultCutMask() { return mMultMaskDevice; } - void setDevicePropagator(const o2::base::PropagatorImpl*) override; + void setDevicePropagator(const o2::base::PropagatorImpl* p) final { this->mPropagatorDevice = p; } // Host-specific getters - gsl::span getNTracklets() { return mNTracklets; } - gsl::span getNCells() { return mNCells; } - std::array& getArrayNCells() { return mNCells; } + gsl::span getNTracklets() { return {mNTracklets.data(), static_cast::size_type>(this->mTrackingTopologyView.nTransitions)}; } + gsl::span getNCells() { return {mNCells.data(), static_cast::size_type>(this->mTrackingTopologyView.nCells)}; } + auto& getArrayNCells() { return mNCells; } + gsl::span getNNeighbours() { return {mNNeighbours.data(), static_cast::size_type>(this->mTrackingTopologyView.nCells)}; } + auto& getArrayNNeighbours() { return mNNeighbours; } // Host-available device getters gsl::span getDeviceTrackletsLUTs() { return mTrackletsLUTDevice; } gsl::span getDeviceCellLUTs() { return mCellsLUTDevice; } - gsl::span getDeviceTracklet() { return mTrackletsDevice; } + gsl::span getDeviceTracklets() { return mTrackletsDevice; } gsl::span getDeviceCells() { return mCellsDevice; } // Overridden getters - int getNumberOfCells() const; + size_t getNumberOfTracklets() const final; + size_t getNumberOfCells() const final; + size_t getNumberOfNeighbours() const final; private: - void allocMemAsync(void**, size_t, Stream*, bool); // Abstract owned and unowned memory allocations - bool mHostRegistered = false; - TimeFrameGPUParameters mGpuParams; + void allocMemAsync(void**, size_t, Stream&, bool, int32_t = o2::gpu::GPUMemoryResource::MEMORY_GPU); // Abstract owned and unowned memory allocations on specific stream + void allocMem(void**, size_t, bool, int32_t = o2::gpu::GPUMemoryResource::MEMORY_GPU); // Abstract owned and unowned memory allocations on default stream // Host-available device buffer sizes - std::array mNTracklets; - std::array mNCells; + std::array mNTracklets{}; + std::array mNCells{}; + std::array mNNeighbours{}; // Device pointers - IndexTableUtils* mIndexTableUtilsDevice; + IndexTableUtilsN* mIndexTableUtilsDevice; + // device navigation views + ROFOverlapTableN::View mDeviceROFOverlapTableView; + ROFVertexLookupTableN::View mDeviceROFVertexLookupTableView; + ROFMaskTableN::View mDeviceROFMaskTableView; + std::vector mDeviceTrackerTopologyViews; + typename TrackingTopologyN::View mDeviceTrackingTopologyView; // Hybrid pref - uint8_t* mMultMaskDevice; Vertex* mPrimaryVerticesDevice; int* mROFramesPVDevice; - std::array mClustersDevice; - std::array mUnsortedClustersDevice; - std::array mClustersIndexTablesDevice; - std::array mUsedClustersDevice; - std::array mROFramesClustersDevice; + std::array mClustersDevice; + std::array mUnsortedClustersDevice; + std::array mClustersIndexTablesDevice; + std::array mUsedClustersDevice; + std::array mROFramesClustersDevice; const Cluster** mClustersDeviceArray; const Cluster** mUnsortedClustersDeviceArray; const int** mClustersIndexTablesDeviceArray; - const unsigned char** mUsedClustersDeviceArray; - const int** mROFrameClustersDeviceArray; - std::array mTrackletsDevice; - Tracklet** mTrackletsDeviceArray; - std::array mTrackletsLUTDevice; - std::array mCellsLUTDevice; - std::array mNeighboursLUTDevice; - - int** mCellsLUTDeviceArray; - int** mNeighboursCellDeviceArray; - int** mNeighboursCellLUTDeviceArray; - int** mTrackletsLUTDeviceArray; - std::array mCellsDevice; - std::array mNeighboursIndexTablesDevice; - CellSeed* mTrackSeedsDevice; + uint8_t** mUsedClustersDeviceArray; + const int** mROFramesClustersDeviceArray; + std::array mTrackletsDevice{}; + std::array mTrackletsLUTDevice{}; + std::array mCellsLUTDevice{}; + std::array mNeighboursLUTDevice{}; + + Tracklet** mTrackletsDeviceArray{nullptr}; + int** mCellsLUTDeviceArray{nullptr}; + int** mNeighboursCellLUTDeviceArray{nullptr}; + int** mTrackletsLUTDeviceArray{nullptr}; + std::array mCellsDevice{}; CellSeed** mCellsDeviceArray; - std::array mCellSeedsDevice; + std::array mNeighboursIndexTablesDevice{}; + TrackSeedN* mTrackSeedsDevice{nullptr}; + int* mTrackSeedsLUTDevice{nullptr}; + unsigned int mNTracks{0}; + std::array mCellSeedsDevice{}; o2::track::TrackParCovF** mCellSeedsDeviceArray; - std::array mCellSeedsChi2Device; + std::array mCellSeedsChi2Device{}; float** mCellSeedsChi2DeviceArray; - Road* mRoadsDevice; TrackITSExt* mTrackITSExtDevice; - std::array*, nLayers - 2> mNeighbourPairsDevice; - std::array mNeighboursDevice; - int** mNeighboursDeviceArray; - std::array mTrackingFrameInfoDevice; + std::array mNeighboursDevice{}; + CellNeighbour** mNeighboursDeviceArray{nullptr}; + std::array mTrackingFrameInfoDevice; const TrackingFrameInfo** mTrackingFrameInfoDeviceArray; // State - std::vector mGpuStreams; - size_t mAvailMemGB; - bool mFirstInit = true; + Streams mGpuStreams; + std::bitset mPinnedUnsortedClusters{0}; + std::bitset mPinnedClusters{0}; + std::bitset mPinnedClustersIndexTables{0}; + std::bitset mPinnedUsedClusters{0}; + std::bitset mPinnedROFramesClusters{0}; + std::bitset mPinnedTrackingFrameInfo{0}; // Temporary buffer for storing output tracks from GPU tracking - std::vector mTrackITSExt; + bounded_vector mTrackITSExt; }; -template -inline int TimeFrameGPU::getNClustersInRofSpan(const int rofIdstart, const int rofSpanSize, const int layerId) const +template +inline std::vector TimeFrameGPU::getClusterSizes() { - return static_cast(mROFramesClusters[layerId][(rofIdstart + rofSpanSize) < mROFramesClusters.size() ? rofIdstart + rofSpanSize : mROFramesClusters.size() - 1] - mROFramesClusters[layerId][rofIdstart]); + std::vector sizes(this->mUnsortedClusters.size()); + std::transform(this->mUnsortedClusters.begin(), this->mUnsortedClusters.end(), sizes.begin(), + [](const auto& v) { return static_cast(v.size()); }); + return sizes; } -template -inline std::vector TimeFrameGPU::getClusterSizes() +template +inline size_t TimeFrameGPU::getNumberOfTracklets() const { - std::vector sizes(mUnsortedClusters.size()); - std::transform(mUnsortedClusters.begin(), mUnsortedClusters.end(), sizes.begin(), - [](const auto& v) { return static_cast(v.size()); }); - return sizes; + return std::accumulate(mNTracklets.begin(), mNTracklets.begin() + this->mTrackingTopologyView.nTransitions, 0); +} + +template +inline size_t TimeFrameGPU::getNumberOfCells() const +{ + return std::accumulate(mNCells.begin(), mNCells.begin() + this->mTrackingTopologyView.nCells, 0); } -template -inline int TimeFrameGPU::getNumberOfCells() const +template +inline size_t TimeFrameGPU::getNumberOfNeighbours() const { - return std::accumulate(mNCells.begin(), mNCells.end(), 0); + return std::accumulate(mNNeighbours.begin(), mNNeighbours.begin() + this->mTrackingTopologyView.nCells, 0); } } // namespace o2::its::gpu diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackerTraitsGPU.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackerTraitsGPU.h index c765307473749..81d870c5b46c2 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackerTraitsGPU.h +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackerTraitsGPU.h @@ -16,29 +16,26 @@ #include "ITStracking/TrackerTraits.h" #include "ITStrackingGPU/TimeFrameGPU.h" -namespace o2 -{ -namespace its +namespace o2::its { -template -class TrackerTraitsGPU final : public TrackerTraits +template +class TrackerTraitsGPU final : public TrackerTraits { + using typename TrackerTraits::IndexTableUtilsN; + public: TrackerTraitsGPU() = default; - ~TrackerTraitsGPU() override = default; + ~TrackerTraitsGPU() final = default; - void adoptTimeFrame(TimeFrame* tf) final; + void adoptTimeFrame(TimeFrame* tf) final; void initialiseTimeFrame(const int iteration) final; - void computeLayerTracklets(const int iteration, int, int) final; + void computeLayerTracklets(const int iteration, int) final; void computeLayerCells(const int iteration) final; void findCellsNeighbours(const int iteration) final; void findRoads(const int iteration) final; - bool supportsExtendTracks() const noexcept final { return false; } - bool supportsFindShortPrimaries() const noexcept final { return false; } - void setBz(float) final; const char* getName() const noexcept final { return "GPU"; } @@ -50,17 +47,10 @@ class TrackerTraitsGPU final : public TrackerTraits int getTFNumberOfCells() const override; private: - IndexTableUtils* mDeviceIndexTableUtils; - gpu::TimeFrameGPU<7>* mTimeFrameGPU; + IndexTableUtilsN* mDeviceIndexTableUtils; + gpu::TimeFrameGPU* mTimeFrameGPU; }; -template -inline void TrackerTraitsGPU::adoptTimeFrame(TimeFrame* tf) -{ - mTimeFrameGPU = static_cast*>(tf); - mTimeFrame = static_cast(tf); -} -} // namespace its -} // namespace o2 +} // namespace o2::its -#endif \ No newline at end of file +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h index 21b14fd9292d2..161283db2a2bc 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h @@ -13,55 +13,39 @@ #ifndef ITSTRACKINGGPU_TRACKINGKERNELS_H_ #define ITSTRACKINGGPU_TRACKINGKERNELS_H_ +#include + +#include "ITStracking/BoundedAllocator.h" +#include "ITStracking/ROFLookupTables.h" +#include "ITStracking/TrackingTopology.h" +#include "ITStrackingGPU/Utils.h" #include "DetectorsBase/Propagator.h" -#include "GPUCommonDef.h" namespace o2::its { class CellSeed; -namespace gpu -{ -#ifdef GPUCA_GPUCODE // GPUg() global kernels must only when compiled by GPU compiler -GPUd() bool fitTrack(TrackITSExt& track, - int start, - int end, - int step, - float chi2clcut, - float chi2ndfcut, - float maxQoverPt, - int nCl, - float Bz, - TrackingFrameInfo** tfInfos, - const o2::base::Propagator* prop, - o2::base::PropagatorF::MatCorrType matCorrType = o2::base::PropagatorImpl::MatCorrType::USEMatCorrNONE); - -template -GPUg() void fitTrackSeedsKernel( - CellSeed* trackSeeds, - const TrackingFrameInfo** foundTrackingFrameInfo, - o2::its::TrackITSExt* tracks, - const float* minPts, - const unsigned int nSeeds, - const float Bz, - const int startLevel, - float maxChi2ClusterAttachment, - float maxChi2NDF, - const o2::base::Propagator* propagator, - const o2::base::PropagatorF::MatCorrType matCorrType = o2::base::PropagatorF::MatCorrType::USEMatCorrLUT); -#endif -} // namespace gpu - -template -void countTrackletsInROFsHandler(const IndexTableUtils* utils, - const uint8_t* multMask, - const int startROF, - const int endROF, - const int maxROF, - const int deltaROF, +struct CellNeighbour; +template +class TrackSeed; +class TrackingFrameInfo; +class Tracklet; +template +class IndexTableUtils; +class Cluster; +class TrackITSExt; +class ExternalAllocator; + +template +void countTrackletsInROFsHandler(const IndexTableUtils* utils, + const typename ROFMaskTable::View& rofMask, + const int transitionId, + const int fromLayer, + const int toLayer, + const typename ROFOverlapTable::View& rofOverlaps, + const typename ROFVertexLookupTable::View& vertexLUT, const int vertexId, const Vertex* vertices, const int* rofPV, - const int nVertices, const Cluster** clusters, std::vector nClusters, const int** ROFClusters, @@ -69,29 +53,30 @@ void countTrackletsInROFsHandler(const IndexTableUtils* utils, const int** clustersIndexTables, int** trackletsLUTs, gsl::span trackletsLUTsHost, - const int iteration, + const bool selectUPCVertices, const float NSigmaCut, - std::vector& phiCuts, + const typename TrackingTopology::View topology, + bounded_vector& transitionPhiCuts, const float resolutionPV, - std::vector& minR, - std::vector& maxR, - std::vector& resolutions, + std::array& minR, + std::array& maxR, + bounded_vector& resolutions, std::vector& radii, - std::vector& mulScatAng, - const int nBlocks, - const int nThreads); - -template -void computeTrackletsInROFsHandler(const IndexTableUtils* utils, - const uint8_t* multMask, - const int startROF, - const int endROF, - const int maxROF, - const int deltaROF, + bounded_vector& transitionMSAngles, + o2::its::ExternalAllocator* alloc, + gpu::Streams& streams); + +template +void computeTrackletsInROFsHandler(const IndexTableUtils* utils, + const typename ROFMaskTable::View& rofMask, + const int transitionId, + const int fromLayer, + const int toLayer, + const typename ROFOverlapTable::View& rofOverlaps, + const typename ROFVertexLookupTable::View& vertexLUT, const int vertexId, const Vertex* vertices, const int* rofPV, - const int nVertices, const Cluster** clusters, std::vector nClusters, const int** ROFClusters, @@ -102,25 +87,28 @@ void computeTrackletsInROFsHandler(const IndexTableUtils* utils, gsl::span nTracklets, int** trackletsLUTs, gsl::span trackletsLUTsHost, - const int iteration, + const bool selectUPCVertices, const float NSigmaCut, - std::vector& phiCuts, + const typename TrackingTopology::View topology, + bounded_vector& transitionPhiCuts, const float resolutionPV, - std::vector& minR, - std::vector& maxR, - std::vector& resolutions, + std::array& minR, + std::array& maxR, + bounded_vector& resolutions, std::vector& radii, - std::vector& mulScatAng, - const int nBlocks, - const int nThreads); + bounded_vector& transitionMSAngles, + o2::its::ExternalAllocator* alloc, + gpu::Streams& streams); +template void countCellsHandler(const Cluster** sortedClusters, const Cluster** unsortedClusters, const TrackingFrameInfo** tfInfo, Tracklet** tracklets, int** trackletsLUT, const int nTracklets, - const int layer, + const int cellTopologyId, + const typename TrackingTopology::View topology, CellSeed* cells, int** cellsLUTsDeviceArray, int* cellsLUTsHost, @@ -128,16 +116,19 @@ void countCellsHandler(const Cluster** sortedClusters, const float maxChi2ClusterAttachment, const float cellDeltaTanLambdaSigma, const float nSigmaCut, - const int nBlocks, - const int nThreads); + const std::vector& layerxX0Host, + o2::its::ExternalAllocator* alloc, + gpu::Streams& streams); +template void computeCellsHandler(const Cluster** sortedClusters, const Cluster** unsortedClusters, const TrackingFrameInfo** tfInfo, Tracklet** tracklets, int** trackletsLUT, const int nTracklets, - const int layer, + const int cellTopologyId, + const typename TrackingTopology::View topology, CellSeed* cells, int** cellsLUTsDeviceArray, int* cellsLUTsHost, @@ -145,72 +136,109 @@ void computeCellsHandler(const Cluster** sortedClusters, const float maxChi2ClusterAttachment, const float cellDeltaTanLambdaSigma, const float nSigmaCut, - const int nBlocks, - const int nThreads); - -unsigned int countCellNeighboursHandler(CellSeed** cellsLayersDevice, - int* neighboursLUTs, - int** cellsLUTs, - gpuPair* cellNeighbours, - int* neighboursIndexTable, - const float maxChi2ClusterAttachment, - const float bz, - const int layerIndex, - const unsigned int nCells, - const unsigned int nCellsNext, - const int maxCellNeighbours, - const int nBlocks, - const int nThreads); + const std::vector& layerxX0Host, + gpu::Streams& streams); + +template +void countCellNeighboursHandler(CellSeed** cellsLayersDevice, + int* neighboursCursor, + int** cellsLUTs, + const int sourceCellTopologyId, + const int targetCellTopologyId, + const float maxChi2ClusterAttachment, + const float bz, + const unsigned int nCells, + gpu::Stream& stream); +void scanCellNeighboursHandler(int* neighboursCursor, + int* neighboursLUT, + const unsigned int nCells, + o2::its::ExternalAllocator* alloc, + gpu::Stream& stream); + +template void computeCellNeighboursHandler(CellSeed** cellsLayersDevice, - int* neighboursLUTs, + int* neighboursCursor, int** cellsLUTs, - gpuPair* cellNeighbours, - int* neighboursIndexTable, + CellNeighbour* cellNeighbours, + const int sourceCellTopologyId, + const int targetCellTopologyId, const float maxChi2ClusterAttachment, const float bz, - const int layerIndex, const unsigned int nCells, - const unsigned int nCellsNext, - const int maxCellNeighbours, - const int nBlocks, - const int nThreads); + gpu::Stream& stream); int filterCellNeighboursHandler(gpuPair*, int*, - unsigned int); + unsigned int, + gpu::Stream&, + o2::its::ExternalAllocator* = nullptr); -template -void processNeighboursHandler(const int startLayer, - const int startLevel, +template +void processNeighboursHandler(const int startLevel, + const int defaultCellTopologyId, CellSeed** allCellSeeds, CellSeed* currentCellSeeds, - std::array& nCells, + const int* currentCellTopologyIds, + const int* currentCellIds, + const int* nCells, const unsigned char** usedClusters, - std::array& neighbours, - gsl::span neighboursDeviceLUTs, + CellNeighbour** neighbours, + int** neighboursDeviceLUTs, const TrackingFrameInfo** foundTrackingFrameInfo, - std::vector& seedsHost, + bounded_vector>& seedsHost, const float bz, const float MaxChi2ClusterAttachment, const float maxChi2NDF, + const int maxHoles, + const int minTrackLength, + const LayerMask holeLayerMask, + const std::vector& layerxX0Host, const o2::base::Propagator* propagator, const o2::base::PropagatorF::MatCorrType matCorrType, - const int nBlocks, - const int nThreads); - -void trackSeedHandler(CellSeed* trackSeeds, - const TrackingFrameInfo** foundTrackingFrameInfo, - o2::its::TrackITSExt* tracks, - std::vector& minPtsHost, - const unsigned int nSeeds, - const float Bz, - const int startLevel, - float maxChi2ClusterAttachment, - float maxChi2NDF, - const o2::base::Propagator* propagator, - const o2::base::PropagatorF::MatCorrType matCorrType, - const int nBlocks, - const int nThreads); + o2::its::ExternalAllocator* alloc); + +template +void countTrackSeedHandler(TrackSeed* trackSeeds, + const TrackingFrameInfo** foundTrackingFrameInfo, + const Cluster** unsortedClusters, + int* seedLUT, + const std::vector& layerRadiiHost, + const std::vector& minPtsHost, + const std::vector& layerxX0Host, + const unsigned int nSeeds, + const float Bz, + const int startLevel, + const float maxChi2ClusterAttachment, + const float maxChi2NDF, + const int reseedIfShorter, + const bool repeatRefitOut, + const bool shiftRefToCluster, + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType, + o2::its::ExternalAllocator* alloc); + +template +void computeTrackSeedHandler(TrackSeed* trackSeeds, + const TrackingFrameInfo** foundTrackingFrameInfo, + const Cluster** unsortedClusters, + o2::its::TrackITSExt* tracks, + const int* seedLUT, + const std::vector& layerRadiiHost, + const std::vector& minPtsHost, + const std::vector& layerxX0Host, + const unsigned int nSeeds, + const unsigned int nTracks, + const float Bz, + const int startLevel, + const float maxChi2ClusterAttachment, + const float maxChi2NDF, + const int reseedIfShorter, + const bool repeatRefitOut, + const bool shiftRefToCluster, + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType, + o2::its::ExternalAllocator* alloc); + } // namespace o2::its #endif // ITSTRACKINGGPU_TRACKINGKERNELS_H_ diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Utils.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Utils.h index 74c118009d67d..bcc20ace7bbc2 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Utils.h +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Utils.h @@ -16,27 +16,50 @@ #ifndef ITSTRACKINGGPU_UTILS_H_ #define ITSTRACKINGGPU_UTILS_H_ +#include +#include +#include + +#include "ITStracking/MathUtils.h" +#include "ITStracking/ExternalAllocator.h" + #include "GPUCommonDef.h" +#include "GPUCommonHelpers.h" +#include "GPUCommonLogger.h" +#include "GPUCommonDefAPI.h" -namespace o2 -{ -namespace its +#ifdef GPUCA_GPUCODE +#include +#ifndef __HIPCC__ +#define THRUST_NAMESPACE thrust::cuda +#else +#define THRUST_NAMESPACE thrust::hip +#endif +#endif + +#ifdef ITS_GPU_LOG +#define GPULog(...) \ + do { \ + LOGP(info, __VA_ARGS__); \ + GPUChkErrS(cudaDeviceSynchronize()); \ + } while (0) +#else +#define GPULog(...) +#endif + +namespace o2::its { +// FWD declarations +template +class IndexTableUtils; +class Tracklet; + template -struct gpuPair { - T1 first; - T2 second; -}; +using gpuPair = std::pair; namespace gpu { -template -void discardResult(const T&) -{ -} - -// Poor man implementation of a span-like struct. It is very limited. template struct gpuSpan { using value_type = T; @@ -80,24 +103,358 @@ struct gpuSpan { unsigned int _size; }; -enum class Task { - Tracker = 0, - Vertexer = 1 +// Abstract stream class +class Stream +{ + public: +#if defined(__HIPCC__) + using Handle = hipStream_t; + static constexpr Handle DefaultStream = 0; + static constexpr unsigned int DefaultFlag = hipStreamNonBlocking; + using Event = hipEvent_t; +#elif defined(__CUDACC__) + using Handle = cudaStream_t; + static constexpr Handle DefaultStream = 0; + static constexpr unsigned int DefaultFlag = cudaStreamNonBlocking; + using Event = cudaEvent_t; +#else + using Handle = void*; + static constexpr Handle DefaultStream = nullptr; + static constexpr unsigned int DefaultFlag = 0; + using Event = void*; +#endif + + Stream(unsigned int flags = DefaultFlag) + { +#if defined(__HIPCC__) + GPUChkErrS(hipStreamCreateWithFlags(&mHandle, flags)); + GPUChkErrS(hipEventCreateWithFlags(&mEvent, hipEventDisableTiming)); +#elif defined(__CUDACC__) + GPUChkErrS(cudaStreamCreateWithFlags(&mHandle, flags)); + GPUChkErrS(cudaEventCreateWithFlags(&mEvent, cudaEventDisableTiming)); +#endif + } + + Stream(Handle h) : mHandle(h) {} + ~Stream() + { + if (mHandle != DefaultStream) { +#if defined(__HIPCC__) + GPUChkErrS(hipStreamDestroy(mHandle)); + GPUChkErrS(hipEventDestroy(mEvent)); +#elif defined(__CUDACC__) + GPUChkErrS(cudaStreamDestroy(mHandle)); + GPUChkErrS(cudaEventDestroy(mEvent)); +#endif + } + } + + operator bool() const { return mHandle != DefaultStream; } + const Handle& get() { return mHandle; } + const Handle& getStream() { return mHandle; } + const Event& getEvent() { return mEvent; } + void sync() const + { +#if defined(__HIPCC__) + GPUChkErrS(hipStreamSynchronize(mHandle)); +#elif defined(__CUDACC__) + GPUChkErrS(cudaStreamSynchronize(mHandle)); +#endif + } + void record() + { +#if defined(__HIPCC__) + GPUChkErrS(hipEventRecord(mEvent, mHandle)); +#elif defined(__CUDACC__) + GPUChkErrS(cudaEventRecord(mEvent, mHandle)); +#endif + } + + private: + Handle mHandle{DefaultStream}; + Event mEvent{nullptr}; +}; + +// Abstract vector for streams. +class Streams +{ + public: + size_t size() const noexcept { return mStreams.size(); } + void resize(size_t n) { mStreams.resize(n); } + void clear() { mStreams.clear(); } + auto& operator[](size_t i) { return mStreams[i]; } + void push_back(const Stream& stream) { mStreams.push_back(stream); } + void sync(bool device = true) + { + if (device) { +#if defined(__HIPCC__) + GPUChkErrS(hipDeviceSynchronize()); +#elif defined(__CUDACC__) + GPUChkErrS(cudaDeviceSynchronize()); +#endif + } else { + for (auto& s : mStreams) { + s.sync(); + } + } + } + void waitEvent(size_t iStream, size_t iEvent) + { +#if defined(__HIPCC__) + GPUChkErrS(hipStreamWaitEvent(mStreams[iStream].get(), mStreams[iEvent].getEvent())); +#elif defined(__CUDACC__) + GPUChkErrS(cudaStreamWaitEvent(mStreams[iStream].get(), mStreams[iEvent].getEvent())); +#endif + } + + private: + std::vector mStreams; +}; + +#ifdef ITS_MEASURE_GPU_TIME +class GPUTimer +{ + public: + GPUTimer(const std::string& name) + : mName(name) + { + mStreams.emplace_back(Stream::DefaultStream); + startTimers(); + } + GPUTimer(Streams& streams, const std::string& name) + : mName(name) + { + for (size_t i{0}; i < streams.size(); ++i) { + mStreams.push_back(streams[i].get()); + } + startTimers(); + } + GPUTimer(Streams& streams, const std::string& name, size_t end, size_t start = 0) + : mName(name) + { + for (size_t sta{start}; sta < end; ++sta) { + mStreams.push_back(streams[sta].get()); + } + startTimers(); + } + GPUTimer(Stream& stream, const std::string& name, const int id = 0) + : mName(name) + { + mStreams.push_back(stream.get()); + mName += ":id" + std::to_string(id); + startTimers(); + } + ~GPUTimer() + { + for (size_t i{0}; i < mStreams.size(); ++i) { + float ms = 0.0f; +#if defined(__HIPCC__) + GPUChkErrS(hipEventRecord(mStops[i], mStreams[i])); + GPUChkErrS(hipEventSynchronize(mStops[i])); + GPUChkErrS(hipEventElapsedTime(&ms, mStarts[i], mStops[i])); + GPUChkErrS(hipEventDestroy(mStarts[i])); + GPUChkErrS(hipEventDestroy(mStops[i])); +#elif defined(__CUDACC__) + GPUChkErrS(cudaEventRecord(mStops[i], mStreams[i])); + GPUChkErrS(cudaEventSynchronize(mStops[i])); + GPUChkErrS(cudaEventElapsedTime(&ms, mStarts[i], mStops[i])); + GPUChkErrS(cudaEventDestroy(mStarts[i])); + GPUChkErrS(cudaEventDestroy(mStops[i])); +#endif + LOGP(info, "Elapsed time for {}:{} {} ms", mName, i, ms); + } + } + + void startTimers() + { + mStarts.resize(mStreams.size()); + mStops.resize(mStreams.size()); + for (size_t i{0}; i < mStreams.size(); ++i) { +#if defined(__HIPCC__) + GPUChkErrS(hipEventCreate(&mStarts[i])); + GPUChkErrS(hipEventCreate(&mStops[i])); + GPUChkErrS(hipEventRecord(mStarts[i], mStreams[i])); +#elif defined(__CUDACC__) + GPUChkErrS(cudaEventCreate(&mStarts[i])); + GPUChkErrS(cudaEventCreate(&mStops[i])); + GPUChkErrS(cudaEventRecord(mStarts[i], mStreams[i])); +#endif + } + } + + private: + std::string mName; + std::vector mStarts, mStops; + std::vector mStreams; }; +#else // ITS_MEASURE_GPU_TIME not defined +class GPUTimer +{ + public: + template + GPUTimer(Args&&...) + { + } +}; +#endif + +#ifdef GPUCA_GPUCODE +template +struct TypedAllocator { + using value_type = T; + using pointer = thrust::device_ptr; + using const_pointer = thrust::device_ptr; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + TypedAllocator() noexcept : mInternalAllocator(nullptr) {} + explicit TypedAllocator(ExternalAllocator* a) noexcept : mInternalAllocator(a) {} + + template + TypedAllocator(const TypedAllocator& o) noexcept : mInternalAllocator(o.mInternalAllocator) + { + } + + pointer allocate(size_type n) + { + void* raw = mInternalAllocator->allocateStack(n * sizeof(T)); + return thrust::device_pointer_cast(static_cast(raw)); + } + + void deallocate(pointer p, size_type n) noexcept + { + if (!p) { + return; + } + void* raw = thrust::raw_pointer_cast(p); + mInternalAllocator->deallocate(static_cast(raw), n * sizeof(T)); + } + + bool operator==(TypedAllocator const& o) const noexcept + { + return mInternalAllocator == o.mInternalAllocator; + } + bool operator!=(TypedAllocator const& o) const noexcept + { + return !(*this == o); + } + + private: + ExternalAllocator* mInternalAllocator; +}; + +GPUdii() gpuSpan getPrimaryVertices(const int rof, + const int* roframesPV, + const int nROF, + const uint8_t* mask, + const Vertex* vertices) +{ + const int start_pv_id = roframesPV[rof]; + const int stop_rof = rof >= nROF - 1 ? nROF : rof + 1; + size_t delta = mask[rof] ? roframesPV[stop_rof] - start_pv_id : 0; // return empty span if ROF is excluded + return gpuSpan(&vertices[start_pv_id], delta); +}; + +GPUdii() gpuSpan getPrimaryVertices(const int romin, + const int romax, + const int* roframesPV, + const int nROF, + const Vertex* vertices) +{ + const int start_pv_id = roframesPV[romin]; + const int stop_rof = romax >= nROF - 1 ? nROF : romax + 1; + return gpuSpan(&vertices[start_pv_id], roframesPV[stop_rof] - roframesPV[romin]); +}; + +GPUdii() gpuSpan getClustersOnLayer(const int rof, + const int totROFs, + const int layer, + const int** roframesClus, + const Cluster** clusters) +{ + if (rof < 0 || rof >= totROFs) { + return gpuSpan(); + } + const int start_clus_id{roframesClus[layer][rof]}; + const int stop_rof = rof >= totROFs - 1 ? totROFs : rof + 1; + const unsigned int delta = roframesClus[layer][stop_rof] - start_clus_id; + return gpuSpan(&(clusters[layer][start_clus_id]), delta); +} + +GPUdii() gpuSpan getTrackletsPerCluster(const int rof, + const int totROFs, + const int mode, + const int** roframesClus, + const Tracklet** tracklets) +{ + if (rof < 0 || rof >= totROFs) { + return gpuSpan(); + } + const int start_clus_id{roframesClus[1][rof]}; + const int stop_rof = rof >= totROFs - 1 ? totROFs : rof + 1; + const unsigned int delta = roframesClus[1][stop_rof] - start_clus_id; + return gpuSpan(&(tracklets[mode][start_clus_id]), delta); +} + +GPUdii() gpuSpan getNTrackletsPerCluster(const int rof, + const int totROFs, + const int mode, + const int** roframesClus, + int** ntracklets) +{ + if (rof < 0 || rof >= totROFs) { + return gpuSpan(); + } + const int start_clus_id{roframesClus[1][rof]}; + const int stop_rof = rof >= totROFs - 1 ? totROFs : rof + 1; + const unsigned int delta = roframesClus[1][stop_rof] - start_clus_id; + return gpuSpan(&(ntracklets[mode][start_clus_id]), delta); +} + +GPUdii() gpuSpan getNTrackletsPerCluster(const int rof, + const int totROFs, + const int mode, + const int** roframesClus, + const int** ntracklets) +{ + if (rof < 0 || rof >= totROFs) { + return gpuSpan(); + } + const int start_clus_id{roframesClus[1][rof]}; + const int stop_rof = rof >= totROFs - 1 ? totROFs : rof + 1; + const unsigned int delta = roframesClus[1][stop_rof] - start_clus_id; + return gpuSpan(&(ntracklets[mode][start_clus_id]), delta); +} -template -GPUhd() T* getPtrFromRuler(int index, T* src, const int* ruler, const int stride = 1) +GPUdii() gpuSpan getNLinesPerCluster(const int rof, + const int totROFs, + const int** roframesClus, + int* nlines) { - return src + ruler[index] * stride; + if (rof < 0 || rof >= totROFs) { + return gpuSpan(); + } + const int start_clus_id{roframesClus[1][rof]}; + const int stop_rof = rof >= totROFs - 1 ? totROFs : rof + 1; + const unsigned int delta = roframesClus[1][stop_rof] - start_clus_id; + return gpuSpan(&(nlines[start_clus_id]), delta); } -template -GPUhd() const T* getPtrFromRuler(int index, const T* src, const int* ruler, const int stride = 1) +GPUdii() gpuSpan getNLinesPerCluster(const int rof, + const int totROFs, + const int** roframesClus, + const int* nlines) { - return src + ruler[index] * stride; + if (rof < 0 || rof >= totROFs) { + return gpuSpan(); + } + const int start_clus_id{roframesClus[1][rof]}; + const int stop_rof = rof >= totROFs - 1 ? totROFs : rof + 1; + const unsigned int delta = roframesClus[1][stop_rof] - start_clus_id; + return gpuSpan(&(nlines[start_clus_id]), delta); } +#endif } // namespace gpu -} // namespace its -} // namespace o2 +} // namespace o2::its -#endif \ No newline at end of file +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/VertexerTraitsGPU.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/VertexerTraitsGPU.h deleted file mode 100644 index eb4dc2179cdb4..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/VertexerTraitsGPU.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file VertexerTraitsGPU.h -/// \brief -/// \author matteo.concas@cern.ch - -// #define VTX_DEBUG -#ifndef ITSTRACKINGGPU_VERTEXERTRAITSGPU_H_ -#define ITSTRACKINGGPU_VERTEXERTRAITSGPU_H_ - -#include -#include - -#include "ITStracking/VertexerTraits.h" -#include "ITStracking/Configuration.h" -#include "ITStracking/Cluster.h" -#include "ITStracking/Constants.h" -#include "ITStracking/Definitions.h" -#include "ITStracking/Tracklet.h" - -#include "ITStrackingGPU/TimeFrameGPU.h" - -namespace o2 -{ -namespace its -{ -class ROframe; - -using constants::its2::InversePhiBinSize; - -class VertexerTraitsGPU : public VertexerTraits -{ - public: - VertexerTraitsGPU(); - ~VertexerTraitsGPU() = default; - void initialise(const TrackingParameters&, const int iteration = 0) override; - void adoptTimeFrame(TimeFrame*) override; - void computeTracklets(const int iteration = 0) override; - void computeTrackletMatching(const int iteration = 0) override; - void computeVertices(const int iteration = 0) override; - void updateVertexingParameters(const std::vector&, const TimeFrameGPUParameters&) override; - - // Hybrid - void initialiseHybrid(const TrackingParameters& pars, const int iteration = 0) override { VertexerTraits::initialise(pars, iteration); } - void computeTrackletsHybrid(const int iteration = 0) override { VertexerTraits::computeTracklets(iteration); } - void computeTrackletMatchingHybrid(const int iteration = 0) override { VertexerTraits::computeTrackletMatching(iteration); } - void computeVerticesHybrid(const int iteration = 0) override { VertexerTraits::computeVertices(iteration); } - void adoptTimeFrameHybrid(TimeFrame* tf) override { VertexerTraits::adoptTimeFrame(tf); } - - void computeVerticesHist(); - - protected: - IndexTableUtils* mDeviceIndexTableUtils; - gpu::TimeFrameGPU<7>* mTimeFrameGPU; - TimeFrameGPUParameters mTfGPUParams; -}; - -inline void VertexerTraitsGPU::adoptTimeFrame(TimeFrame* tf) -{ - mTimeFrameGPU = static_cast*>(tf); - mTimeFrame = static_cast(tf); -} - -} // namespace its -} // namespace o2 -#endif diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/VertexingKernels.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/VertexingKernels.h deleted file mode 100644 index 6ae042d081688..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/VertexingKernels.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// - -#ifndef ITSTRACKINGGPU_VERTEXINGKERNELS_H_ -#define ITSTRACKINGGPU_VERTEXINGKERNELS_H_ -#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/VertexerTraitsGPU.h" -#include "ITStrackingGPU/TracerGPU.h" - -#include "GPUCommonArray.h" - -namespace o2::its::gpu -{ -#ifdef GPUCA_GPUCODE // GPUg() global kernels must only when compiled by GPU compiler -template -GPUg() void trackleterKernelMultipleRof( - const Cluster* clustersNextLayer, // 0 2 - const Cluster* clustersCurrentLayer, // 1 1 - const int* sizeNextLClusters, - const int* sizeCurrentLClusters, - const int* nextIndexTables, - Tracklet* Tracklets, - int* foundTracklets, - const IndexTableUtils* utils, - const unsigned int startRofId, - const unsigned int rofSize, - const float phiCut, - const size_t maxTrackletsPerCluster); -#endif -template -void trackletFinderHandler(const Cluster* clustersNextLayer, // 0 2 - const Cluster* clustersCurrentLayer, // 1 1 - const int* sizeNextLClusters, - const int* sizeCurrentLClusters, - const int* nextIndexTables, - Tracklet* Tracklets, - int* foundTracklets, - const IndexTableUtils* utils, - const unsigned int startRofId, - const unsigned int rofSize, - const float phiCut, - const size_t maxTrackletsPerCluster = 1e2); -} // namespace o2::its::gpu -#endif \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/CMakeLists.txt b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/CMakeLists.txt index 9769930504f29..38f11265682ce 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/CMakeLists.txt @@ -11,29 +11,30 @@ # CUDA if(CUDA_ENABLED) -find_package(CUDAToolkit) -message(STATUS "Building ITS CUDA tracker") -# add_compile_options(-O0 -g -lineinfo -fPIC) -# add_compile_definitions(ITS_MEASURE_GPU_TIME) -o2_add_library(ITStrackingCUDA - SOURCES ClusterLinesGPU.cu - TrackerTraitsGPU.cxx - TimeFrameGPU.cu - TracerGPU.cu - TrackingKernels.cu - VertexingKernels.cu - VertexerTraitsGPU.cxx - PUBLIC_INCLUDE_DIRECTORIES ../ - PUBLIC_LINK_LIBRARIES O2::ITStracking - O2::SimConfig - O2::SimulationDataFormat - O2::ReconstructionDataFormats - O2::GPUCommon - PRIVATE_LINK_LIBRARIES O2::GPUTrackingCUDAExternalProvider - TARGETVARNAME targetName) - -set_property(TARGET ${targetName} PROPERTY CUDA_SEPARABLE_COMPILATION ON) -target_compile_definitions(${targetName} PRIVATE $) -set_target_cuda_arch(${targetName}) + find_package(CUDAToolkit) + message(STATUS "Building ITS CUDA tracker") + o2_add_library(ITStrackingCUDA + SOURCES TrackerTraitsGPU.cxx + TimeFrameGPU.cu + TrackingKernels.cu + PUBLIC_INCLUDE_DIRECTORIES ../ + PUBLIC_LINK_LIBRARIES O2::ITStracking + O2::MathUtils + O2::SimConfig + O2::SimulationDataFormat + O2::ReconstructionDataFormats + O2::GPUCommon + PRIVATE_LINK_LIBRARIES O2::GPUTrackingCUDAExternalProvider + TARGETVARNAME targetName) + set_target_gpu_arch("CUDA" ${targetName}) + # Enable relocatable device code (needed for separable compilation + debugging) + set_property(TARGET ${targetName} PROPERTY CUDA_SEPARABLE_COMPILATION ON) + target_compile_options(${targetName} PRIVATE + $<$:-diag-error=20014> + # $<$:-G;-O0;-Xptxas=-O0> + # $<$:-O0;-g> + ) + # target_compile_definitions(${targetName} PRIVATE ITS_MEASURE_GPU_TIME ITS_GPU_LOG) + target_compile_definitions(${targetName} PRIVATE $) endif() diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/ClusterLinesGPU.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/ClusterLinesGPU.cu deleted file mode 100644 index 79f4e40dc5f10..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/ClusterLinesGPU.cu +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \author matteo.concas@cern.ch - -#include -#include "ITStrackingGPU/ClusterLinesGPU.h" - -namespace o2 -{ -namespace its -{ -namespace gpu -{ - -GPUd() ClusterLinesGPU::ClusterLinesGPU(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; - } - - double 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]; - double 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 ClusterLinesGPU::computeClusterCentroid() -{ - - double 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 diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameChunk.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameChunk.cu deleted file mode 100644 index c8512e667aea8..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameChunk.cu +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include -#include -#include - -#include "ITStracking/Constants.h" - -#include "ITStrackingGPU/Utils.h" -#include "ITStrackingGPU/TracerGPU.h" - -#include "ITStrackingGPU/TimeFrameChunk.h" - -#include -#include - -#include "GPUCommonDef.h" -#include "GPUCommonMath.h" -#include "GPUCommonLogger.h" -#include "GPUCommonHelpers.h" - -#ifndef __HIPCC__ -#define THRUST_NAMESPACE thrust::cuda -#else -#define THRUST_NAMESPACE thrust::hip -#endif - -namespace o2::its -{ -using constants::GB; -using constants::MB; -namespace gpu -{ - -template -GpuTimeFrameChunk::~GpuTimeFrameChunk() -{ - if (mAllocated) { - for (int i = 0; i < nLayers; ++i) { - GPUChkErrS(cudaFree(mClustersDevice[i])); - // GPUChkErrS(cudaFree(mTrackingFrameInfoDevice[i])); - GPUChkErrS(cudaFree(mClusterExternalIndicesDevice[i])); - GPUChkErrS(cudaFree(mIndexTablesDevice[i])); - if (i < nLayers - 1) { - GPUChkErrS(cudaFree(mTrackletsDevice[i])); - GPUChkErrS(cudaFree(mTrackletsLookupTablesDevice[i])); - if (i < nLayers - 2) { - GPUChkErrS(cudaFree(mCellsDevice[i])); - GPUChkErrS(cudaFree(mCellsLookupTablesDevice[i])); - GPUChkErrS(cudaFree(mRoadsLookupTablesDevice[i])); - if (i < nLayers - 3) { - GPUChkErrS(cudaFree(mNeighboursCellLookupTablesDevice[i])); - GPUChkErrS(cudaFree(mNeighboursCellDevice[i])); - } - } - } - } - // GPUChkErrS(cudaFree(mRoadsDevice)); - GPUChkErrS(cudaFree(mCUBTmpBufferDevice)); - GPUChkErrS(cudaFree(mFoundTrackletsDevice)); - GPUChkErrS(cudaFree(mNFoundCellsDevice)); - GPUChkErrS(cudaFree(mCellsDeviceArray)); - GPUChkErrS(cudaFree(mNeighboursCellDeviceArray)); - GPUChkErrS(cudaFree(mNeighboursCellLookupTablesDeviceArray)); - } -} - -template -void GpuTimeFrameChunk::allocate(const size_t nrof, Stream& stream) -{ - RANGE("device_partition_allocation", 2); - mNRof = nrof; - // for (int i = 0; i < nLayers; ++i) { - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mClustersDevice[i])), sizeof(Cluster) * mTFGPUParams->clustersPerROfCapacity * nrof, &stream, true); - // // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mTrackingFrameInfoDevice[i])), sizeof(TrackingFrameInfo) * mTFGPUParams->clustersPerROfCapacity * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mClusterExternalIndicesDevice[i])), sizeof(int) * mTFGPUParams->clustersPerROfCapacity * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mIndexTablesDevice[i])), sizeof(int) * (256 * 128 + 1) * nrof, &stream, true); - // if (i < nLayers - 1) { - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mTrackletsLookupTablesDevice[i])), sizeof(int) * mTFGPUParams->clustersPerROfCapacity * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mTrackletsDevice[i])), sizeof(Tracklet) * mTFGPUParams->maxTrackletsPerCluster * mTFGPUParams->clustersPerROfCapacity * nrof, &stream, true); - // if (i < nLayers - 2) { - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mCellsLookupTablesDevice[i])), sizeof(int) * mTFGPUParams->validatedTrackletsCapacity * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mCellsDevice[i])), sizeof(CellSeed) * mTFGPUParams->maxNeighboursSize * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mRoadsLookupTablesDevice[i]), sizeof(int) * mTFGPUParams->maxNeighboursSize * nrof, &stream, true); - // if (i < nLayers - 3) { - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mNeighboursCellLookupTablesDevice[i])), sizeof(int) * mTFGPUParams->maxNeighboursSize * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mNeighboursCellDevice[i])), sizeof(int) * mTFGPUParams->maxNeighboursSize * nrof, &stream, true); - // } - // if (i < 2) { - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mNTrackletsPerClusterDevice[i])), sizeof(int) * mTFGPUParams->clustersPerROfCapacity * nrof, &stream, true); - // } - // } - // } - // } - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mCUBTmpBufferDevice), mTFGPUParams->tmpCUBBufferSize * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mLinesDevice), sizeof(Line) * mTFGPUParams->maxTrackletsPerCluster * mTFGPUParams->clustersPerROfCapacity * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mNFoundLinesDevice), sizeof(int) * mTFGPUParams->clustersPerROfCapacity * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mNExclusiveFoundLinesDevice), sizeof(int) * mTFGPUParams->clustersPerROfCapacity * nrof + 1, &stream, true); // + 1 for cub::DeviceScan::ExclusiveSum, to cover cases where we have maximum number of clusters per ROF - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mUsedTrackletsDevice), sizeof(unsigned char) * mTFGPUParams->maxTrackletsPerCluster * mTFGPUParams->clustersPerROfCapacity * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mClusteredLinesDevice), sizeof(int) * mTFGPUParams->clustersPerROfCapacity * mTFGPUParams->maxTrackletsPerCluster * nrof, &stream, true); - // // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mRoadsDevice), sizeof(Road) * mTFGPUParams->maxRoadPerRofSize * nrof, &stream, true); - - // /// Invariant allocations - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mFoundTrackletsDevice), (nLayers - 1) * sizeof(int) * nrof, &stream, true); // No need to reset, we always read it after writing - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mNFoundCellsDevice), (nLayers - 2) * sizeof(int) * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mCellsDeviceArray), (nLayers - 2) * sizeof(CellSeed*), &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mNeighboursCellDeviceArray), (nLayers - 3) * sizeof(int*), &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mNeighboursCellLookupTablesDeviceArray), (nLayers - 3) * sizeof(int*), &stream, true); - - // /// Copy pointers of allocated memory to regrouping arrays - // GPUChkErrS(cudaMemcpyAsync(mCellsDeviceArray, mCellsDevice.data(), (nLayers - 2) * sizeof(CellSeed*), cudaMemcpyHostToDevice, stream.get())); - // GPUChkErrS(cudaMemcpyAsync(mNeighboursCellDeviceArray, mNeighboursCellDevice.data(), (nLayers - 3) * sizeof(int*), cudaMemcpyHostToDevice, stream.get())); - // GPUChkErrS(cudaMemcpyAsync(mNeighboursCellLookupTablesDeviceArray, mNeighboursCellLookupTablesDevice.data(), (nLayers - 3) * sizeof(int*), cudaMemcpyHostToDevice, stream.get())); - - mAllocated = true; -} - -template -void GpuTimeFrameChunk::reset(const Task task, Stream& stream) -{ - RANGE("buffer_reset", 0); - // if ((bool)task) { // Vertexer-only initialisation (cannot be constexpr: due to the presence of gpu raw calls can't be put in header) - // for (int i = 0; i < 2; i++) { - // auto thrustTrackletsBegin = thrust::device_ptr(mTrackletsDevice[i]); - // auto thrustTrackletsEnd = thrustTrackletsBegin + mTFGPUParams->maxTrackletsPerCluster * mTFGPUParams->clustersPerROfCapacity * mNRof; - // thrust::fill(THRUST_NAMESPACE::par.on(stream.get()), thrustTrackletsBegin, thrustTrackletsEnd, Tracklet{}); - // GPUChkErrS(cudaMemsetAsync(mNTrackletsPerClusterDevice[i], 0, sizeof(int) * mTFGPUParams->clustersPerROfCapacity * mNRof, stream.get())); - // } - // GPUChkErrS(cudaMemsetAsync(mUsedTrackletsDevice, false, sizeof(unsigned char) * mTFGPUParams->maxTrackletsPerCluster * mTFGPUParams->clustersPerROfCapacity * mNRof, stream.get())); - // GPUChkErrS(cudaMemsetAsync(mClusteredLinesDevice, -1, sizeof(int) * mTFGPUParams->clustersPerROfCapacity * mTFGPUParams->maxTrackletsPerCluster * mNRof, stream.get())); - // } else { - // for (int i = 0; i < nLayers; ++i) { - // if (i < nLayers - 1) { - // GPUChkErrS(cudaMemsetAsync(mTrackletsLookupTablesDevice[i], 0, sizeof(int) * mTFGPUParams->clustersPerROfCapacity * mNRof, stream.get())); - // auto thrustTrackletsBegin = thrust::device_ptr(mTrackletsDevice[i]); - // auto thrustTrackletsEnd = thrustTrackletsBegin + mTFGPUParams->maxTrackletsPerCluster * mTFGPUParams->clustersPerROfCapacity * mNRof; - // thrust::fill(THRUST_NAMESPACE::par.on(stream.get()), thrustTrackletsBegin, thrustTrackletsEnd, Tracklet{}); - // if (i < nLayers - 2) { - // GPUChkErrS(cudaMemsetAsync(mCellsLookupTablesDevice[i], 0, sizeof(int) * mTFGPUParams->cellsLUTsize * mNRof, stream.get())); - // GPUChkErrS(cudaMemsetAsync(mRoadsLookupTablesDevice[i], 0, sizeof(int) * mTFGPUParams->maxNeighboursSize * mNRof, stream.get())); - // if (i < nLayers - 3) { - // GPUChkErrS(cudaMemsetAsync(mNeighboursCellLookupTablesDevice[i], 0, sizeof(int) * mTFGPUParams->maxNeighboursSize * mNRof, stream.get())); - // GPUChkErrS(cudaMemsetAsync(mNeighboursCellDevice[i], 0, sizeof(int) * mTFGPUParams->maxNeighboursSize * mNRof, stream.get())); - // } - // } - // } - // } - // GPUChkErrS(cudaMemsetAsync(mNFoundCellsDevice, 0, (nLayers - 2) * sizeof(int), stream.get())); - // } -} - -template -size_t GpuTimeFrameChunk::computeScalingSizeBytes(const int nrof, const TimeFrameGPUParameters& config) -{ - size_t rofsize = nLayers * sizeof(int); // number of clusters per ROF - // rofsize += nLayers * sizeof(Cluster) * config.clustersPerROfCapacity; // clusters - // rofsize += nLayers * sizeof(TrackingFrameInfo) * config.clustersPerROfCapacity; // tracking frame info - // rofsize += nLayers * sizeof(int) * config.clustersPerROfCapacity; // external cluster indices - // rofsize += nLayers * sizeof(int) * (256 * 128 + 1); // index tables - // rofsize += (nLayers - 1) * sizeof(int) * config.clustersPerROfCapacity; // tracklets lookup tables - // rofsize += (nLayers - 1) * sizeof(Tracklet) * config.maxTrackletsPerCluster * config.clustersPerROfCapacity; // tracklets - // rofsize += 2 * sizeof(int) * config.clustersPerROfCapacity; // tracklets found per cluster (vertexer) - // rofsize += sizeof(unsigned char) * config.maxTrackletsPerCluster * config.clustersPerROfCapacity; // used tracklets (vertexer) - // rofsize += (nLayers - 2) * sizeof(int) * config.validatedTrackletsCapacity; // cells lookup tables - // rofsize += (nLayers - 2) * sizeof(CellSeed) * config.maxNeighboursSize; // cells - // rofsize += (nLayers - 3) * sizeof(int) * config.maxNeighboursSize; // cell neighbours lookup tables - // rofsize += (nLayers - 3) * sizeof(int) * config.maxNeighboursSize; // cell neighbours - // rofsize += sizeof(Road) * config.maxRoadPerRofSize; // roads - // rofsize += (nLayers - 2) * sizeof(int) * config.maxNeighboursSize; // road LUT - // rofsize += sizeof(Line) * config.maxTrackletsPerCluster * config.clustersPerROfCapacity; // lines - // rofsize += sizeof(int) * config.clustersPerROfCapacity; // found lines - // rofsize += sizeof(int) * config.clustersPerROfCapacity; // found lines exclusive sum - // rofsize += sizeof(int) * config.clustersPerROfCapacity * config.maxTrackletsPerCluster; // lines used in clusterlines - - // rofsize += (nLayers - 1) * sizeof(int); // total found tracklets - // rofsize += (nLayers - 2) * sizeof(int); // total found cells - - return rofsize * nrof; -} - -template -size_t GpuTimeFrameChunk::computeFixedSizeBytes(const TimeFrameGPUParameters& config) -{ - size_t total = config.tmpCUBBufferSize; // CUB tmp buffers - total += sizeof(gpu::StaticTrackingParameters); // static parameters loaded once - return total; -} - -template -size_t GpuTimeFrameChunk::computeRofPerChunk(const TimeFrameGPUParameters& config, const size_t m) -{ - return (m * GB / (float)(config.nTimeFrameChunks) - GpuTimeFrameChunk::computeFixedSizeBytes(config)) / (float)GpuTimeFrameChunk::computeScalingSizeBytes(1, config); -} - -/// Interface -template -Cluster* GpuTimeFrameChunk::getDeviceClusters(const int layer) -{ - return mClustersDevice[layer]; -} - -template -int* GpuTimeFrameChunk::getDeviceClusterExternalIndices(const int layer) -{ - return mClusterExternalIndicesDevice[layer]; -} - -template -int* GpuTimeFrameChunk::getDeviceIndexTables(const int layer) -{ - return mIndexTablesDevice[layer]; -} - -template -Tracklet* GpuTimeFrameChunk::getDeviceTracklets(const int layer) -{ - return mTrackletsDevice[layer]; -} - -template -int* GpuTimeFrameChunk::getDeviceTrackletsLookupTables(const int layer) -{ - return mTrackletsLookupTablesDevice[layer]; -} - -template -CellSeed* GpuTimeFrameChunk::getDeviceCells(const int layer) -{ - return mCellsDevice[layer]; -} - -template -int* GpuTimeFrameChunk::getDeviceCellsLookupTables(const int layer) -{ - return mCellsLookupTablesDevice[layer]; -} - -template -int* GpuTimeFrameChunk::getDeviceCellNeigboursLookupTables(const int layer) -{ - return mNeighboursCellLookupTablesDevice[layer]; -} - -template -int* GpuTimeFrameChunk::getDeviceCellNeighbours(const int layer) -{ - return mNeighboursCellDevice[layer]; -} - -template -int* GpuTimeFrameChunk::getDeviceRoadsLookupTables(const int layer) -{ - return mRoadsLookupTablesDevice[layer]; -} - -// Load data -template -size_t GpuTimeFrameChunk::loadDataOnDevice(const size_t startRof, const size_t maxRof, const int maxLayers, Stream& stream) -{ - RANGE("load_clusters_data", 5); - // auto nRofs = std::min(maxRof - startRof, mNRof); - // mNPopulatedRof = mTimeFramePtr->getNClustersROFrange(startRof, nRofs, 0).size(); - // for (int i = 0; i < maxLayers; ++i) { - // mHostClusters[i] = mTimeFramePtr->getClustersPerROFrange(startRof, nRofs, i); - // mHostIndexTables[i] = mTimeFramePtr->getIndexTablePerROFrange(startRof, nRofs, i); - // if (mHostClusters[i].size() > mTFGPUParams->clustersPerROfCapacity * nRofs) { - // LOGP(warning, "Clusters on layer {} exceed the expected value, resizing to config value: {}, will lose information!", i, mTFGPUParams->clustersPerROfCapacity * nRofs); - // } - // GPUChkErrS(cudaMemcpyAsync(mClustersDevice[i], - // mHostClusters[i].data(), - // (int)std::min(mHostClusters[i].size(), mTFGPUParams->clustersPerROfCapacity * nRofs) * sizeof(Cluster), - // cudaMemcpyHostToDevice, stream.get())); - // if (mHostIndexTables[i].data()) { - // GPUChkErrS(cudaMemcpyAsync(mIndexTablesDevice[i], - // mHostIndexTables[i].data(), - // mHostIndexTables[i].size() * sizeof(int), - // cudaMemcpyHostToDevice, stream.get())); - // } - // } - return mNPopulatedRof; // return the number of ROFs we loaded the data for. -} -template class GpuTimeFrameChunk<7>; -} // namespace gpu -} // namespace o2::its \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu index ee99955ba6669..5fff30f5162b1 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu @@ -9,566 +9,750 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. /// + #include -#include -#include -#include "ITStracking/Constants.h" +#include +#include -#include "ITStrackingGPU/Utils.h" #include "ITStrackingGPU/TimeFrameGPU.h" -#include "ITStrackingGPU/TracerGPU.h" - -#include -#include -#include +#include "ITStracking/Constants.h" +#include "ITStracking/BoundedAllocator.h" +#include "ITStrackingGPU/Utils.h" #include "GPUCommonDef.h" #include "GPUCommonMath.h" #include "GPUCommonLogger.h" #include "GPUCommonHelpers.h" +#include "utils/strtag.h" -#ifdef ITS_MEASURE_GPU_TIME -#define START_GPU_STREAM_TIMER(stream, name) \ - cudaEvent_t event_start, event_stop; \ - GPUChkErrS(cudaEventCreate(&event_start)); \ - GPUChkErrS(cudaEventCreate(&event_stop)); \ - GPUChkErrS(cudaEventRecord(event_start, stream)); \ - const std::string task_name = name; - -#define STOP_GPU_STREAM_TIMER(stream) \ - GPUChkErrS(cudaEventRecord(event_stop, stream)); \ - GPUChkErrS(cudaEventSynchronize(event_stop)); \ - float ms; \ - GPUChkErrS(cudaEventElapsedTime(&ms, event_start, event_stop)); \ - std::cout << "Elapsed time for " << task_name << ": " << ms << " ms" << std::endl; \ - GPUChkErrS(cudaEventDestroy(event_start)); \ - GPUChkErrS(cudaEventDestroy(event_stop)); -#else -#define START_GPU_STREAM_TIMER(stream, name) -#define STOP_GPU_STREAM_TIMER(stream) -#endif - -namespace o2 -{ -namespace its +namespace o2::its::gpu { -using constants::GB; -using constants::MB; -namespace gpu -{ -class Stream final +template +void TimeFrameGPU::allocMemAsync(void** ptr, size_t size, Stream& stream, bool extAllocator, int32_t type) { - public: - Stream(); - ~Stream(); - - [[nodiscard]] const cudaStream_t& get() const; - - private: - cudaStream_t mStream; -}; - -Stream::Stream() -{ - GPUChkErrS(cudaStreamCreate(&mStream)); + if (extAllocator) { + *ptr = (this->mExternalAllocator)->allocate(size, type); + } else { + GPULog("Calling default CUDA allocator"); + GPUChkErrS(cudaMallocAsync(reinterpret_cast(ptr), size, stream.get())); + } } -Stream::~Stream() +template +void TimeFrameGPU::allocMem(void** ptr, size_t size, bool extAllocator, int32_t type) { - GPUChkErrS(cudaStreamDestroy(mStream)); + if (extAllocator) { + *ptr = (this->mExternalAllocator)->allocate(size, type); + } else { + GPULog("Calling default CUDA allocator"); + GPUChkErrS(cudaMalloc(reinterpret_cast(ptr), size)); + } } -const cudaStream_t& Stream::get() const +template +void TimeFrameGPU::loadIndexTableUtils() { - return mStream; + GPUTimer timer("loading indextable utils"); + { + GPULog("gpu-allocation: allocating IndexTableUtils buffer, for {:.2f} MB.", sizeof(IndexTableUtilsN) / constants::MB); + allocMem(reinterpret_cast(&mIndexTableUtilsDevice), sizeof(IndexTableUtilsN), this->hasFrameworkAllocator()); + } + GPULog("gpu-transfer: loading IndexTableUtils object, for {:.2f} MB.", sizeof(IndexTableUtilsN) / constants::MB); + GPUChkErrS(cudaMemcpy(mIndexTableUtilsDevice, &(this->mIndexTableUtils), sizeof(IndexTableUtilsN), cudaMemcpyHostToDevice)); +} + +template +void TimeFrameGPU::createUnsortedClustersDeviceArray(const int maxLayers) +{ + { + GPUTimer timer("creating unsorted clusters array"); + allocMem(reinterpret_cast(&mUnsortedClustersDeviceArray), NLayers * sizeof(Cluster*), this->hasFrameworkAllocator()); + GPUChkErrS(cudaHostRegister(mUnsortedClustersDevice.data(), NLayers * sizeof(Cluster*), cudaHostRegisterPortable)); + mPinnedUnsortedClusters.set(NLayers); + if (!this->hasFrameworkAllocator()) { + for (auto iLayer{0}; iLayer < o2::gpu::CAMath::Min(maxLayers, NLayers); ++iLayer) { + GPUChkErrS(cudaHostRegister(this->mUnsortedClusters[iLayer].data(), this->mUnsortedClusters[iLayer].size() * sizeof(Cluster), cudaHostRegisterPortable)); + mPinnedUnsortedClusters.set(iLayer); + } + } + } } -void* DefaultGPUAllocator::allocate(size_t size) +template +void TimeFrameGPU::loadUnsortedClustersDevice(const int layer) { - LOGP(fatal, "Called DefaultGPUAllocator::allocate with size {}", size); - return nullptr; // to be implemented + { + GPUTimer timer(mGpuStreams[layer], "loading unsorted clusters", layer); + GPULog("gpu-transfer: loading {} unsorted clusters on layer {}, for {:.2f} MB.", this->mUnsortedClusters[layer].size(), layer, this->mUnsortedClusters[layer].size() * sizeof(Cluster) / constants::MB); + allocMemAsync(reinterpret_cast(&mUnsortedClustersDevice[layer]), this->mUnsortedClusters[layer].size() * sizeof(Cluster), mGpuStreams[layer], this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemcpyAsync(mUnsortedClustersDevice[layer], this->mUnsortedClusters[layer].data(), this->mUnsortedClusters[layer].size() * sizeof(Cluster), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); + GPUChkErrS(cudaMemcpyAsync(&mUnsortedClustersDeviceArray[layer], &mUnsortedClustersDevice[layer], sizeof(Cluster*), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); + } } -template -TimeFrameGPU::TimeFrameGPU() +template +void TimeFrameGPU::createClustersDeviceArray(const int maxLayers) { - mIsGPU = true; + { + GPUTimer timer("creating sorted clusters array"); + allocMem(reinterpret_cast(&mClustersDeviceArray), NLayers * sizeof(Cluster*), this->hasFrameworkAllocator()); + GPUChkErrS(cudaHostRegister(mClustersDevice.data(), NLayers * sizeof(Cluster*), cudaHostRegisterPortable)); + mPinnedClusters.set(NLayers); + if (!this->hasFrameworkAllocator()) { + for (auto iLayer{0}; iLayer < o2::gpu::CAMath::Min(maxLayers, NLayers); ++iLayer) { + GPUChkErrS(cudaHostRegister(this->mClusters[iLayer].data(), this->mClusters[iLayer].size() * sizeof(Cluster), cudaHostRegisterPortable)); + mPinnedClusters.set(iLayer); + } + } + } } -template -TimeFrameGPU::~TimeFrameGPU() = default; - -template -void TimeFrameGPU::allocMemAsync(void** ptr, size_t size, Stream* strPtr, bool extAllocator) +template +void TimeFrameGPU::loadClustersDevice(const int layer) { - if (extAllocator) { - *ptr = mAllocator->allocate(size); - } else { - LOGP(debug, "Calling default CUDA allocator"); - GPUChkErrS(cudaMallocAsync(reinterpret_cast(ptr), size, strPtr->get())); + { + GPUTimer timer(mGpuStreams[layer], "loading sorted clusters", layer); + GPULog("gpu-transfer: loading {} clusters on layer {}, for {:.2f} MB.", this->mClusters[layer].size(), layer, this->mClusters[layer].size() * sizeof(Cluster) / constants::MB); + allocMemAsync(reinterpret_cast(&mClustersDevice[layer]), this->mClusters[layer].size() * sizeof(Cluster), mGpuStreams[layer], this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemcpyAsync(mClustersDevice[layer], this->mClusters[layer].data(), this->mClusters[layer].size() * sizeof(Cluster), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); + GPUChkErrS(cudaMemcpyAsync(&mClustersDeviceArray[layer], &mClustersDevice[layer], sizeof(Cluster*), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); } } -template -void TimeFrameGPU::setDevicePropagator(const o2::base::PropagatorImpl* propagator) +template +void TimeFrameGPU::createClustersIndexTablesArray() { - mPropagatorDevice = propagator; + { + GPUTimer timer("creating clustersindextable array"); + allocMem(reinterpret_cast(&mClustersIndexTablesDeviceArray), NLayers * sizeof(int*), this->hasFrameworkAllocator()); + GPUChkErrS(cudaHostRegister(mClustersIndexTablesDevice.data(), NLayers * sizeof(int*), cudaHostRegisterPortable)); + mPinnedClustersIndexTables.set(NLayers); + if (!this->hasFrameworkAllocator()) { + for (auto iLayer{0}; iLayer < NLayers; ++iLayer) { + GPUChkErrS(cudaHostRegister(this->mIndexTables[iLayer].data(), this->mIndexTables[iLayer].size() * sizeof(int), cudaHostRegisterPortable)); + mPinnedClustersIndexTables.set(iLayer); + } + } + } } -template -void TimeFrameGPU::loadIndexTableUtils(const int iteration) +template +void TimeFrameGPU::loadClustersIndexTables(const int layer) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "loading indextable utils"); - if (!iteration) { - LOGP(debug, "gpu-allocation: allocating IndexTableUtils buffer, for {} MB.", sizeof(IndexTableUtils) / MB); - allocMemAsync(reinterpret_cast(&mIndexTableUtilsDevice), sizeof(IndexTableUtils), nullptr, getExtAllocator()); + { + GPUTimer timer(mGpuStreams[layer], "loading sorted clusters", layer); + GPULog("gpu-transfer: loading clusters indextable for layer {} with {} elements, for {:.2f} MB.", layer, this->mIndexTables[layer].size(), this->mIndexTables[layer].size() * sizeof(int) / constants::MB); + allocMemAsync(reinterpret_cast(&mClustersIndexTablesDevice[layer]), this->mIndexTables[layer].size() * sizeof(int), mGpuStreams[layer], this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemcpyAsync(mClustersIndexTablesDevice[layer], this->mIndexTables[layer].data(), this->mIndexTables[layer].size() * sizeof(int), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); + GPUChkErrS(cudaMemcpyAsync(&mClustersIndexTablesDeviceArray[layer], &mClustersIndexTablesDevice[layer], sizeof(int*), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); } - LOGP(debug, "gpu-transfer: loading IndexTableUtils object, for {} MB.", sizeof(IndexTableUtils) / MB); - GPUChkErrS(cudaMemcpyAsync(mIndexTableUtilsDevice, &mIndexTableUtils, sizeof(IndexTableUtils), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); } -template -void TimeFrameGPU::loadUnsortedClustersDevice(const int iteration) +template +void TimeFrameGPU::createUsedClustersDeviceArray(const int maxLayers) { - if (!iteration) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "loading unsorted clusters"); - for (auto iLayer{0}; iLayer < nLayers; ++iLayer) { - LOGP(debug, "gpu-transfer: loading {} unsorted clusters on layer {}, for {} MB.", mUnsortedClusters[iLayer].size(), iLayer, mUnsortedClusters[iLayer].size() * sizeof(Cluster) / MB); - allocMemAsync(reinterpret_cast(&mUnsortedClustersDevice[iLayer]), mUnsortedClusters[iLayer].size() * sizeof(Cluster), nullptr, getExtAllocator()); - GPUChkErrS(cudaHostRegister(mUnsortedClusters[iLayer].data(), mUnsortedClusters[iLayer].size() * sizeof(Cluster), cudaHostRegisterPortable)); - GPUChkErrS(cudaMemcpyAsync(mUnsortedClustersDevice[iLayer], mUnsortedClusters[iLayer].data(), mUnsortedClusters[iLayer].size() * sizeof(Cluster), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); + { + GPUTimer timer("creating used clusters flags"); + allocMem(reinterpret_cast(&mUsedClustersDeviceArray), NLayers * sizeof(uint8_t*), this->hasFrameworkAllocator()); + GPUChkErrS(cudaHostRegister(mUsedClustersDevice.data(), NLayers * sizeof(uint8_t*), cudaHostRegisterPortable)); + mPinnedUsedClusters.set(NLayers); + if (!this->hasFrameworkAllocator()) { + for (auto iLayer{0}; iLayer < o2::gpu::CAMath::Min(maxLayers, NLayers); ++iLayer) { + GPUChkErrS(cudaHostRegister(this->mUsedClusters[iLayer].data(), this->mUsedClusters[iLayer].size() * sizeof(uint8_t), cudaHostRegisterPortable)); + mPinnedUsedClusters.set(iLayer); + } } - allocMemAsync(reinterpret_cast(&mUnsortedClustersDeviceArray), nLayers * sizeof(Cluster*), nullptr, getExtAllocator()); - GPUChkErrS(cudaHostRegister(mUnsortedClustersDevice.data(), nLayers * sizeof(Cluster*), cudaHostRegisterPortable)); - GPUChkErrS(cudaMemcpyAsync(mUnsortedClustersDeviceArray, mUnsortedClustersDevice.data(), nLayers * sizeof(Cluster*), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); } } -template -void TimeFrameGPU::loadClustersDevice(const int iteration) +template +void TimeFrameGPU::createUsedClustersDevice(const int layer) { - if (!iteration) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "loading sorted clusters"); - for (auto iLayer{0}; iLayer < nLayers; ++iLayer) { - LOGP(debug, "gpu-transfer: loading {} clusters on layer {}, for {} MB.", mClusters[iLayer].size(), iLayer, mClusters[iLayer].size() * sizeof(Cluster) / MB); - allocMemAsync(reinterpret_cast(&mClustersDevice[iLayer]), mClusters[iLayer].size() * sizeof(Cluster), nullptr, getExtAllocator()); - GPUChkErrS(cudaHostRegister(mClusters[iLayer].data(), mClusters[iLayer].size() * sizeof(Cluster), cudaHostRegisterPortable)); - GPUChkErrS(cudaMemcpyAsync(mClustersDevice[iLayer], mClusters[iLayer].data(), mClusters[iLayer].size() * sizeof(Cluster), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); - } - allocMemAsync(reinterpret_cast(&mClustersDeviceArray), nLayers * sizeof(Cluster*), nullptr, getExtAllocator()); - GPUChkErrS(cudaHostRegister(mClustersDevice.data(), nLayers * sizeof(Cluster*), cudaHostRegisterPortable)); - GPUChkErrS(cudaMemcpyAsync(mClustersDeviceArray, mClustersDevice.data(), nLayers * sizeof(Cluster*), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); + { + GPUTimer timer(mGpuStreams[layer], "creating used clusters flags", layer); + GPULog("gpu-transfer: creating {} used clusters flags on layer {}, for {:.2f} MB.", this->mUsedClusters[layer].size(), layer, this->mUsedClusters[layer].size() * sizeof(unsigned char) / constants::MB); + allocMemAsync(reinterpret_cast(&mUsedClustersDevice[layer]), this->mUsedClusters[layer].size() * sizeof(unsigned char), mGpuStreams[layer], this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemsetAsync(mUsedClustersDevice[layer], 0, this->mUsedClusters[layer].size() * sizeof(unsigned char), mGpuStreams[layer].get())); + GPUChkErrS(cudaMemcpyAsync(&mUsedClustersDeviceArray[layer], &mUsedClustersDevice[layer], sizeof(unsigned char*), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); } } -template -void TimeFrameGPU::loadClustersIndexTables(const int iteration) +template +void TimeFrameGPU::loadUsedClustersDevice() { - if (!iteration) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "loading sorted clusters"); - for (auto iLayer{0}; iLayer < nLayers; ++iLayer) { - LOGP(debug, "gpu-transfer: loading clusters indextable for layer {} with {} elements, for {} MB.", iLayer, mIndexTables[iLayer].size(), mIndexTables[iLayer].size() * sizeof(int) / MB); - allocMemAsync(reinterpret_cast(&mClustersIndexTablesDevice[iLayer]), mIndexTables[iLayer].size() * sizeof(int), nullptr, getExtAllocator()); - GPUChkErrS(cudaMemcpyAsync(mClustersIndexTablesDevice[iLayer], mIndexTables[iLayer].data(), mIndexTables[iLayer].size() * sizeof(int), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); - } - allocMemAsync(reinterpret_cast(&mClustersIndexTablesDeviceArray), nLayers * sizeof(int), nullptr, getExtAllocator()); - GPUChkErrS(cudaMemcpyAsync(mClustersIndexTablesDeviceArray, mClustersIndexTablesDevice.data(), nLayers * sizeof(int*), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); + for (auto iLayer{0}; iLayer < NLayers; ++iLayer) { + GPUTimer timer(mGpuStreams[iLayer], "loading used clusters flags", iLayer); + GPULog("gpu-transfer: loading {} used clusters flags on layer {}, for {:.2f} MB.", this->mUsedClusters[iLayer].size(), iLayer, this->mUsedClusters[iLayer].size() * sizeof(unsigned char) / constants::MB); + GPUChkErrS(cudaMemcpyAsync(mUsedClustersDevice[iLayer], this->mUsedClusters[iLayer].data(), this->mUsedClusters[iLayer].size() * sizeof(unsigned char), cudaMemcpyHostToDevice, mGpuStreams[iLayer].get())); } } -template -void TimeFrameGPU::createUsedClustersDevice(const int iteration) +template +void TimeFrameGPU::createROFrameClustersDeviceArray() { - if (!iteration) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "creating used clusters flags"); - for (auto iLayer{0}; iLayer < nLayers; ++iLayer) { - LOGP(debug, "gpu-transfer: creating {} used clusters flags on layer {}, for {} MB.", mUsedClusters[iLayer].size(), iLayer, mUsedClusters[iLayer].size() * sizeof(unsigned char) / MB); - allocMemAsync(reinterpret_cast(&mUsedClustersDevice[iLayer]), mUsedClusters[iLayer].size() * sizeof(unsigned char), nullptr, getExtAllocator()); - GPUChkErrS(cudaMemsetAsync(mUsedClustersDevice[iLayer], 0, mUsedClusters[iLayer].size() * sizeof(unsigned char), mGpuStreams[0]->get())); + { + GPUTimer timer("creating ROFrame clusters array"); + allocMem(reinterpret_cast(&mROFramesClustersDeviceArray), NLayers * sizeof(int*), this->hasFrameworkAllocator()); + GPUChkErrS(cudaHostRegister(mROFramesClustersDevice.data(), NLayers * sizeof(int*), cudaHostRegisterPortable)); + mPinnedROFramesClusters.set(NLayers); + if (!this->hasFrameworkAllocator()) { + for (auto iLayer{0}; iLayer < NLayers; ++iLayer) { + GPUChkErrS(cudaHostRegister(this->mROFramesClusters[iLayer].data(), this->mROFramesClusters[iLayer].size() * sizeof(int), cudaHostRegisterPortable)); + mPinnedROFramesClusters.set(iLayer); + } } - allocMemAsync(reinterpret_cast(&mUsedClustersDeviceArray), nLayers * sizeof(unsigned char*), nullptr, getExtAllocator()); - GPUChkErrS(cudaMemcpyAsync(mUsedClustersDeviceArray, mUsedClustersDevice.data(), nLayers * sizeof(unsigned char*), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); } } -template -void TimeFrameGPU::loadUsedClustersDevice() +template +void TimeFrameGPU::loadROFrameClustersDevice(const int layer) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "loading used clusters flags"); - for (auto iLayer{0}; iLayer < nLayers; ++iLayer) { - LOGP(debug, "gpu-transfer: loading {} used clusters flags on layer {}, for {} MB.", mUsedClusters[iLayer].size(), iLayer, mClusters[iLayer].size() * sizeof(unsigned char) / MB); - GPUChkErrS(cudaMemcpyAsync(mUsedClustersDevice[iLayer], mUsedClusters[iLayer].data(), mUsedClusters[iLayer].size() * sizeof(unsigned char), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); + { + GPUTimer timer(mGpuStreams[layer], "loading ROframe clusters", layer); + GPULog("gpu-transfer: loading {} ROframe clusters info on layer {}, for {:.2f} MB.", this->mROFramesClusters[layer].size(), layer, this->mROFramesClusters[layer].size() * sizeof(int) / constants::MB); + allocMemAsync(reinterpret_cast(&mROFramesClustersDevice[layer]), this->mROFramesClusters[layer].size() * sizeof(int), mGpuStreams[layer], this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemcpyAsync(mROFramesClustersDevice[layer], this->mROFramesClusters[layer].data(), this->mROFramesClusters[layer].size() * sizeof(int), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); + GPUChkErrS(cudaMemcpyAsync(&mROFramesClustersDeviceArray[layer], &mROFramesClustersDevice[layer], sizeof(int*), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); } - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); } -template -void TimeFrameGPU::loadROframeClustersDevice(const int iteration) +template +void TimeFrameGPU::createTrackingFrameInfoDeviceArray() { - if (!iteration) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "loading ROframe clusters"); - for (auto iLayer{0}; iLayer < nLayers; ++iLayer) { - LOGP(debug, "gpu-transfer: loading {} ROframe clusters info on layer {}, for {} MB.", mROFramesClusters[iLayer].size(), iLayer, mROFramesClusters[iLayer].size() * sizeof(int) / MB); - allocMemAsync(reinterpret_cast(&mROFramesClustersDevice[iLayer]), mROFramesClusters[iLayer].size() * sizeof(int), nullptr, getExtAllocator()); - GPUChkErrS(cudaMemcpyAsync(mROFramesClustersDevice[iLayer], mROFramesClusters[iLayer].data(), mROFramesClusters[iLayer].size() * sizeof(int), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); + { + GPUTimer timer("creating trackingframeinfo array"); + allocMem(reinterpret_cast(&mTrackingFrameInfoDeviceArray), NLayers * sizeof(TrackingFrameInfo*), this->hasFrameworkAllocator()); + GPUChkErrS(cudaHostRegister(mTrackingFrameInfoDevice.data(), NLayers * sizeof(TrackingFrameInfo*), cudaHostRegisterPortable)); + mPinnedTrackingFrameInfo.set(NLayers); + if (!this->hasFrameworkAllocator()) { + for (auto iLayer{0}; iLayer < NLayers; ++iLayer) { + GPUChkErrS(cudaHostRegister(this->mTrackingFrameInfo[iLayer].data(), this->mTrackingFrameInfo[iLayer].size() * sizeof(TrackingFrameInfo), cudaHostRegisterPortable)); + mPinnedTrackingFrameInfo.set(iLayer); + } } - allocMemAsync(reinterpret_cast(&mROFrameClustersDeviceArray), nLayers * sizeof(int*), nullptr, getExtAllocator()); - GPUChkErrS(cudaMemcpyAsync(mROFrameClustersDeviceArray, mROFramesClustersDevice.data(), nLayers * sizeof(int*), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); } } -template -void TimeFrameGPU::loadTrackingFrameInfoDevice(const int iteration) +template +void TimeFrameGPU::loadTrackingFrameInfoDevice(const int layer) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "loading trackingframeinfo"); - if (!iteration) { - for (auto iLayer{0}; iLayer < nLayers; ++iLayer) { - LOGP(debug, "gpu-transfer: loading {} tfinfo on layer {}, for {} MB.", mTrackingFrameInfo[iLayer].size(), iLayer, mTrackingFrameInfo[iLayer].size() * sizeof(TrackingFrameInfo) / MB); - allocMemAsync(reinterpret_cast(&mTrackingFrameInfoDevice[iLayer]), mTrackingFrameInfo[iLayer].size() * sizeof(TrackingFrameInfo), nullptr, getExtAllocator()); - GPUChkErrS(cudaHostRegister(mTrackingFrameInfo[iLayer].data(), mTrackingFrameInfo[iLayer].size() * sizeof(TrackingFrameInfo), cudaHostRegisterPortable)); - GPUChkErrS(cudaMemcpyAsync(mTrackingFrameInfoDevice[iLayer], mTrackingFrameInfo[iLayer].data(), mTrackingFrameInfo[iLayer].size() * sizeof(TrackingFrameInfo), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); - } - allocMemAsync(reinterpret_cast(&mTrackingFrameInfoDeviceArray), nLayers * sizeof(TrackingFrameInfo*), nullptr, getExtAllocator()); - GPUChkErrS(cudaHostRegister(mTrackingFrameInfoDevice.data(), nLayers * sizeof(TrackingFrameInfo*), cudaHostRegisterPortable)); - GPUChkErrS(cudaMemcpyAsync(mTrackingFrameInfoDeviceArray, mTrackingFrameInfoDevice.data(), nLayers * sizeof(TrackingFrameInfo*), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); + { + GPUTimer timer(mGpuStreams[layer], "loading trackingframeinfo", layer); + GPULog("gpu-transfer: loading {} tfinfo on layer {}, for {:.2f} MB.", this->mTrackingFrameInfo[layer].size(), layer, this->mTrackingFrameInfo[layer].size() * sizeof(TrackingFrameInfo) / constants::MB); + allocMemAsync(reinterpret_cast(&mTrackingFrameInfoDevice[layer]), this->mTrackingFrameInfo[layer].size() * sizeof(TrackingFrameInfo), mGpuStreams[layer], this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemcpyAsync(mTrackingFrameInfoDevice[layer], this->mTrackingFrameInfo[layer].data(), this->mTrackingFrameInfo[layer].size() * sizeof(TrackingFrameInfo), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); + GPUChkErrS(cudaMemcpyAsync(&mTrackingFrameInfoDeviceArray[layer], &mTrackingFrameInfoDevice[layer], sizeof(TrackingFrameInfo*), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); } - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); } -template -void TimeFrameGPU::loadMultiplicityCutMask(const int iteration) -{ - if (!iteration) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "loading multiplicity cut mask"); - LOGP(debug, "gpu-transfer: loading multiplicity cut mask with {} elements, for {} MB.", mMultiplicityCutMask.size(), mMultiplicityCutMask.size() * sizeof(bool) / MB); - allocMemAsync(reinterpret_cast(&mMultMaskDevice), mMultiplicityCutMask.size() * sizeof(uint8_t), nullptr, getExtAllocator()); - GPUChkErrS(cudaMemcpyAsync(mMultMaskDevice, mMultiplicityCutMask.data(), mMultiplicityCutMask.size() * sizeof(uint8_t), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); +template +void TimeFrameGPU::loadROFCutMask(const int iteration) +{ + { + GPUTimer timer("loading multiplicity cut mask"); + const auto& hostTable = *(this->mROFMask); + const auto hostView = hostTable.getView(); + using TableEntry = ROFMaskTable::TableEntry; + using TableIndex = ROFMaskTable::TableIndex; + TableEntry* d_flatTable{nullptr}; + TableIndex* d_indices{nullptr}; + GPULog("gpu-transfer: iteration {} loading multiplicity cut mask with {} elements, for {:.2f} MB.", + iteration, hostTable.getFlatMaskSize(), hostTable.getFlatMaskSize() * sizeof(TableEntry) / constants::MB); + allocMem(reinterpret_cast(&d_flatTable), hostTable.getFlatMaskSize() * sizeof(TableEntry), this->hasFrameworkAllocator()); + allocMem(reinterpret_cast(&d_indices), NLayers * sizeof(uint32_t), this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemcpy(d_indices, hostView.mLayerROFOffsets, NLayers * sizeof(TableIndex), cudaMemcpyHostToDevice)); + // Re-copy the flat mask on every qualifying iteration (e.g. after swapMasks() for UPC) + GPUChkErrS(cudaMemcpy(d_flatTable, hostView.mFlatMask, hostTable.getFlatMaskSize() * sizeof(TableEntry), cudaMemcpyHostToDevice)); + mDeviceROFMaskTableView = hostTable.getDeviceView(d_flatTable, d_indices); } } -template -void TimeFrameGPU::loadVertices(const int iteration) +template +void TimeFrameGPU::loadVertices() { - if (!iteration) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "loading seeding vertices"); - LOGP(debug, "gpu-transfer: loading {} ROframes vertices, for {} MB.", mROFramesPV.size(), mROFramesPV.size() * sizeof(int) / MB); - allocMemAsync(reinterpret_cast(&mROFramesPVDevice), mROFramesPV.size() * sizeof(int), nullptr, getExtAllocator()); - GPUChkErrS(cudaMemcpyAsync(mROFramesPVDevice, mROFramesPV.data(), mROFramesPV.size() * sizeof(int), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); - LOGP(debug, "gpu-transfer: loading {} seeding vertices, for {} MB.", mPrimaryVertices.size(), mPrimaryVertices.size() * sizeof(Vertex) / MB); - allocMemAsync(reinterpret_cast(&mPrimaryVerticesDevice), mPrimaryVertices.size() * sizeof(Vertex), nullptr, getExtAllocator()); - GPUChkErrS(cudaMemcpyAsync(mPrimaryVerticesDevice, mPrimaryVertices.data(), mPrimaryVertices.size() * sizeof(Vertex), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); + { + GPUTimer timer("loading seeding vertices"); + GPULog("gpu-transfer: loading {} seeding vertices, for {:.2f} MB.", this->mPrimaryVertices.size(), this->mPrimaryVertices.size() * sizeof(Vertex) / constants::MB); + allocMem(reinterpret_cast(&mPrimaryVerticesDevice), this->mPrimaryVertices.size() * sizeof(Vertex), this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemcpy(mPrimaryVerticesDevice, this->mPrimaryVertices.data(), this->mPrimaryVertices.size() * sizeof(Vertex), cudaMemcpyHostToDevice)); + } +} + +template +void TimeFrameGPU::loadROFOverlapTable() +{ + { + GPUTimer timer("initialising device view of ROFOverlapTable"); + const auto& hostTable = this->getROFOverlapTable(); + const auto& hostView = this->getROFOverlapTableView(); + using TableEntry = ROFOverlapTable::TableEntry; + using TableIndex = ROFOverlapTable::TableIndex; + using LayerTiming = o2::its::LayerTiming; + TableEntry* d_flatTable{nullptr}; + TableIndex* d_indices{nullptr}; + LayerTiming* d_layers{nullptr}; + size_t flatTableSize = hostTable.getFlatTableSize(); + allocMem(reinterpret_cast(&d_flatTable), flatTableSize * sizeof(TableEntry), this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemcpy(d_flatTable, hostView.mFlatTable, flatTableSize * sizeof(TableEntry), cudaMemcpyHostToDevice)); + allocMem(reinterpret_cast(&d_indices), hostTable.getIndicesSize() * sizeof(TableIndex), this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemcpy(d_indices, hostView.mIndices, hostTable.getIndicesSize() * sizeof(TableIndex), cudaMemcpyHostToDevice)); + allocMem(reinterpret_cast(&d_layers), NLayers * sizeof(LayerTiming), this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemcpy(d_layers, hostView.mLayers, NLayers * sizeof(LayerTiming), cudaMemcpyHostToDevice)); + mDeviceROFOverlapTableView = hostTable.getDeviceView(d_flatTable, d_indices, d_layers); + } +} + +template +void TimeFrameGPU::loadROFVertexLookupTable() +{ + { + GPUTimer timer("initialising device view of ROFVertexLookupTable"); + const auto& hostTable = this->getROFVertexLookupTable(); + const auto& hostView = this->getROFVertexLookupTableView(); + using TableEntry = ROFVertexLookupTable::TableEntry; + using TableIndex = ROFVertexLookupTable::TableIndex; + using LayerTiming = o2::its::LayerTiming; + TableEntry* d_flatTable{nullptr}; + TableIndex* d_indices{nullptr}; + LayerTiming* d_layers{nullptr}; + size_t flatTableSize = hostTable.getFlatTableSize(); + allocMem(reinterpret_cast(&d_flatTable), flatTableSize * sizeof(TableEntry), this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemcpy(d_flatTable, hostView.mFlatTable, flatTableSize * sizeof(TableEntry), cudaMemcpyHostToDevice)); + allocMem(reinterpret_cast(&d_indices), hostTable.getIndicesSize() * sizeof(TableIndex), this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemcpy(d_indices, hostView.mIndices, hostTable.getIndicesSize() * sizeof(TableIndex), cudaMemcpyHostToDevice)); + allocMem(reinterpret_cast(&d_layers), NLayers * sizeof(LayerTiming), this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemcpy(d_layers, hostView.mLayers, NLayers * sizeof(LayerTiming), cudaMemcpyHostToDevice)); + mDeviceROFVertexLookupTableView = hostTable.getDeviceView(d_flatTable, d_indices, d_layers); + } +} + +template +void TimeFrameGPU::loadTrackingTopologies() +{ + GPUTimer timer("initialising device views of TrackingTopology"); + const auto& hostTopologies = this->getTrackerTopologies(); + mDeviceTrackerTopologyViews.resize(hostTopologies.size()); + using LayerTransition = typename TrackingTopologyN::LayerTransition; + using CellTopology = typename TrackingTopologyN::CellTopology; + using Range = typename TrackingTopologyN::Range; + using Id = typename TrackingTopologyN::Id; + for (size_t iteration = 0; iteration < hostTopologies.size(); ++iteration) { + const auto& topology = hostTopologies[iteration]; + LayerTransition* dTransitions{nullptr}; + CellTopology* dCells{nullptr}; + Range* dCellsByFirstTransitionIndex{nullptr}; + Id* dCellsByFirstTransition{nullptr}; + allocMem(reinterpret_cast(&dTransitions), topology.getNTransitions() * sizeof(LayerTransition), this->hasFrameworkAllocator()); + allocMem(reinterpret_cast(&dCells), topology.getNCells() * sizeof(CellTopology), this->hasFrameworkAllocator()); + allocMem(reinterpret_cast(&dCellsByFirstTransitionIndex), topology.getNTransitions() * sizeof(Range), this->hasFrameworkAllocator()); + allocMem(reinterpret_cast(&dCellsByFirstTransition), topology.getNCellsByFirstTransition() * sizeof(Id), this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemcpy(dTransitions, topology.getTransitions().data(), topology.getNTransitions() * sizeof(LayerTransition), cudaMemcpyHostToDevice)); + GPUChkErrS(cudaMemcpy(dCells, topology.getCells().data(), topology.getNCells() * sizeof(CellTopology), cudaMemcpyHostToDevice)); + GPUChkErrS(cudaMemcpy(dCellsByFirstTransitionIndex, topology.getCellsByFirstTransitionIndex().data(), topology.getNTransitions() * sizeof(Range), cudaMemcpyHostToDevice)); + GPUChkErrS(cudaMemcpy(dCellsByFirstTransition, topology.getCellsByFirstTransition().data(), topology.getNCellsByFirstTransition() * sizeof(Id), cudaMemcpyHostToDevice)); + mDeviceTrackerTopologyViews[iteration] = topology.getDeviceView(dTransitions, dCells, dCellsByFirstTransitionIndex, dCellsByFirstTransition); + } + if (!mDeviceTrackerTopologyViews.empty()) { + mDeviceTrackingTopologyView = mDeviceTrackerTopologyViews.front(); } } -template -void TimeFrameGPU::createTrackletsLUTDevice(const int iteration) +template +void TimeFrameGPU::updateROFVertexLookupTable() { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "creating tracklets LUTs"); - for (auto iLayer{0}; iLayer < nLayers - 1; ++iLayer) { - if (!iteration) { - LOGP(debug, "gpu-transfer: creating tracklets LUT for {} elements on layer {}, for {} MB.", mClusters[iLayer].size() + 1, iLayer, (mClusters[iLayer].size() + 1) * sizeof(int) / MB); - allocMemAsync(reinterpret_cast(&mTrackletsLUTDevice[iLayer]), (mClusters[iLayer].size() + 1) * sizeof(int), nullptr, getExtAllocator()); - } - GPUChkErrS(cudaMemsetAsync(mTrackletsLUTDevice[iLayer], 0, (mClusters[iLayer].size() + 1) * sizeof(int), mGpuStreams[0]->get())); + const auto& hostTable = this->getROFVertexLookupTable(); + { + GPUTimer timer("updating device view of ROFVertexLookupTable"); + const auto& hostView = this->getROFVertexLookupTableView(); + using TableEntry = ROFVertexLookupTable::TableEntry; + TableEntry* d_flatTable{nullptr}; + size_t flatTableSize = hostTable.getFlatTableSize(); + allocMem(reinterpret_cast(&d_flatTable), flatTableSize * sizeof(TableEntry), this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemcpy(d_flatTable, hostView.mFlatTable, flatTableSize * sizeof(TableEntry), cudaMemcpyHostToDevice)); + mDeviceROFVertexLookupTableView = hostTable.getDeviceView(d_flatTable, hostView.mIndices, hostView.mLayers); } - if (!iteration) { - allocMemAsync(reinterpret_cast(&mTrackletsLUTDeviceArray), (nLayers - 1) * sizeof(int*), nullptr, getExtAllocator()); - GPUChkErrS(cudaMemcpyAsync(mTrackletsLUTDeviceArray, mTrackletsLUTDevice.data(), mTrackletsLUTDevice.size() * sizeof(int*), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); +} + +template +void TimeFrameGPU::createTrackletsLUTDeviceArray() +{ + { + allocMem(reinterpret_cast(&mTrackletsLUTDeviceArray), MaxTransitions * sizeof(int*), this->hasFrameworkAllocator()); } - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); } -template -void TimeFrameGPU::createTrackletsBuffers() +template +void TimeFrameGPU::createTrackletsLUTDevice(bool allocate, const int layer) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "creating cells buffers"); - for (auto iLayer{0}; iLayer < nLayers - 1; ++iLayer) { - mNTracklets[iLayer] = 0; - GPUChkErrS(cudaMemcpyAsync(&mNTracklets[iLayer], mTrackletsLUTDevice[iLayer] + mClusters[iLayer].size(), sizeof(int), cudaMemcpyDeviceToHost)); - LOGP(debug, "gpu-transfer: creating tracklets buffer for {} elements on layer {}, for {} MB.", mNTracklets[iLayer], iLayer, mNTracklets[iLayer] * sizeof(Tracklet) / MB); - allocMemAsync(reinterpret_cast(&mTrackletsDevice[iLayer]), mNTracklets[iLayer] * sizeof(Tracklet), nullptr, getExtAllocator()); + GPUTimer timer(mGpuStreams[layer], "creating tracklets LUTs", layer); + const int fromLayer = this->mTrackingTopologyView.getTransition(layer).fromLayer; + const int ncls = this->mClusters[fromLayer].size() + 1; + if (allocate || mTrackletsLUTDevice[layer] == nullptr) { + GPULog("gpu-allocation: creating tracklets LUT for {} elements on layer {}, for {:.2f} MB.", ncls, layer, ncls * sizeof(int) / constants::MB); + allocMemAsync(reinterpret_cast(&mTrackletsLUTDevice[layer]), ncls * sizeof(int), mGpuStreams[layer], this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemcpyAsync(&mTrackletsLUTDeviceArray[layer], &mTrackletsLUTDevice[layer], sizeof(int*), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); } - allocMemAsync(reinterpret_cast(&mTrackletsDeviceArray), (nLayers - 1) * sizeof(Tracklet*), nullptr, getExtAllocator()); - GPUChkErrS(cudaHostRegister(mTrackletsDevice.data(), (nLayers - 1) * sizeof(Tracklet*), cudaHostRegisterPortable)); - GPUChkErrS(cudaMemcpyAsync(mTrackletsDeviceArray, mTrackletsDevice.data(), (nLayers - 1) * sizeof(Tracklet*), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); + GPUChkErrS(cudaMemsetAsync(mTrackletsLUTDevice[layer], 0, ncls * sizeof(int), mGpuStreams[layer].get())); } -template -void TimeFrameGPU::loadTrackletsDevice() +template +void TimeFrameGPU::createTrackletsBuffersArray() { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "loading tracklets"); - for (auto iLayer{0}; iLayer < nLayers - 1; ++iLayer) { - LOGP(debug, "gpu-transfer: loading {} tracklets on layer {}, for {} MB.", mTracklets[iLayer].size(), iLayer, mTracklets[iLayer].size() * sizeof(Tracklet) / MB); - GPUChkErrS(cudaHostRegister(mTracklets[iLayer].data(), mTracklets[iLayer].size() * sizeof(Tracklet), cudaHostRegisterPortable)); - GPUChkErrS(cudaMemcpyAsync(mTrackletsDevice[iLayer], mTracklets[iLayer].data(), mTracklets[iLayer].size() * sizeof(Tracklet), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); + { + GPUTimer timer("creating tracklet buffers array"); + allocMem(reinterpret_cast(&mTrackletsDeviceArray), MaxTransitions * sizeof(Tracklet*), this->hasFrameworkAllocator()); } - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); } -template -void TimeFrameGPU::loadTrackletsLUTDevice() +template +void TimeFrameGPU::createTrackletsBuffers(const int layer) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "loading tracklets"); - for (auto iLayer{0}; iLayer < nLayers - 2; ++iLayer) { - LOGP(debug, "gpu-transfer: loading tracklets LUT for {} elements on layer {}, for {} MB", mTrackletsLookupTable[iLayer].size(), iLayer + 1, mTrackletsLookupTable[iLayer].size() * sizeof(int) / MB); - GPUChkErrS(cudaHostRegister(mTrackletsLookupTable[iLayer].data(), mTrackletsLookupTable[iLayer].size() * sizeof(int), cudaHostRegisterPortable)); - GPUChkErrS(cudaMemcpyAsync(mTrackletsLUTDevice[iLayer + 1], mTrackletsLookupTable[iLayer].data(), mTrackletsLookupTable[iLayer].size() * sizeof(int), cudaMemcpyHostToDevice)); + GPUTimer timer(mGpuStreams[layer], "creating tracklet buffers", layer); + mNTracklets[layer] = 0; + const int fromLayer = this->mTrackingTopologyView.getTransition(layer).fromLayer; + GPUChkErrS(cudaMemcpyAsync(&mNTracklets[layer], mTrackletsLUTDevice[layer] + this->mClusters[fromLayer].size(), sizeof(int), cudaMemcpyDeviceToHost, mGpuStreams[layer].get())); + mGpuStreams[layer].sync(); // ensure number of tracklets is correct + GPULog("gpu-transfer: creating tracklets buffer for {} elements on layer {}, for {:.2f} MB.", mNTracklets[layer], layer, mNTracklets[layer] * sizeof(Tracklet) / constants::MB); + allocMemAsync(reinterpret_cast(&mTrackletsDevice[layer]), mNTracklets[layer] * sizeof(Tracklet), mGpuStreams[layer], this->hasFrameworkAllocator(), (o2::gpu::GPUMemoryResource::MEMORY_GPU | o2::gpu::GPUMemoryResource::MEMORY_STACK)); + GPUChkErrS(cudaMemsetAsync(mTrackletsDevice[layer], 0, mNTracklets[layer] * sizeof(Tracklet), mGpuStreams[layer].get())); + GPUChkErrS(cudaMemcpyAsync(&mTrackletsDeviceArray[layer], &mTrackletsDevice[layer], sizeof(Tracklet*), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); +} + +template +void TimeFrameGPU::loadTrackletsDevice() +{ + GPUTimer timer(mGpuStreams, "loading tracklets", NLayers - 1); + for (auto iLayer{0}; iLayer < NLayers - 1; ++iLayer) { + GPULog("gpu-transfer: loading {} tracklets on layer {}, for {:.2f} MB.", this->mTracklets[iLayer].size(), iLayer, this->mTracklets[iLayer].size() * sizeof(Tracklet) / constants::MB); + GPUChkErrS(cudaHostRegister(this->mTracklets[iLayer].data(), this->mTracklets[iLayer].size() * sizeof(Tracklet), cudaHostRegisterPortable)); + GPUChkErrS(cudaMemcpyAsync(mTrackletsDevice[iLayer], this->mTracklets[iLayer].data(), this->mTracklets[iLayer].size() * sizeof(Tracklet), cudaMemcpyHostToDevice, mGpuStreams[iLayer].get())); } - GPUChkErrS(cudaHostRegister(mTrackletsLUTDevice.data(), (nLayers - 1) * sizeof(int*), cudaHostRegisterPortable)); - GPUChkErrS(cudaMemcpyAsync(mTrackletsLUTDeviceArray, mTrackletsLUTDevice.data(), (nLayers - 1) * sizeof(int*), cudaMemcpyHostToDevice)); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); } -template -void TimeFrameGPU::createNeighboursIndexTablesDevice() +template +void TimeFrameGPU::loadTrackletsLUTDevice() { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "creating cells neighbours"); - // Here we do also the creation of the CellsDeviceArray, as the cells buffers are populated separately in the previous steps. - allocMemAsync(reinterpret_cast(&mCellsDeviceArray), (nLayers - 2) * sizeof(CellSeed*), nullptr, getExtAllocator()); - GPUChkErrS(cudaHostRegister(mCellsDevice.data(), (nLayers - 2) * sizeof(CellSeed*), cudaHostRegisterPortable)); - GPUChkErrS(cudaMemcpyAsync(mCellsDeviceArray, mCellsDevice.data(), (nLayers - 2) * sizeof(CellSeed*), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); - for (auto iLayer{0}; iLayer < nLayers - 2; ++iLayer) { - LOGP(debug, "gpu-transfer: loading neighbours LUT for {} elements on layer {}, for {} MB.", mNCells[iLayer], iLayer, mNCells[iLayer] * sizeof(CellSeed) / MB); - allocMemAsync(reinterpret_cast(&mNeighboursIndexTablesDevice[iLayer]), (mNCells[iLayer] + 1) * sizeof(int), nullptr, getExtAllocator()); - GPUChkErrS(cudaMemsetAsync(mNeighboursIndexTablesDevice[iLayer], 0, (mNCells[iLayer] + 1) * sizeof(int), mGpuStreams[0]->get())); + GPUTimer timer("loading tracklets"); + for (auto iLayer{0}; iLayer < NLayers - 2; ++iLayer) { + GPULog("gpu-transfer: loading tracklets LUT for {} elements on layer {}, for {:.2f} MB", this->mTrackletsLookupTable[iLayer].size(), iLayer + 1, this->mTrackletsLookupTable[iLayer].size() * sizeof(int) / constants::MB); + GPUChkErrS(cudaMemcpyAsync(mTrackletsLUTDevice[iLayer + 1], this->mTrackletsLookupTable[iLayer].data(), this->mTrackletsLookupTable[iLayer].size() * sizeof(int), cudaMemcpyHostToDevice, mGpuStreams[iLayer].get())); } - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); + mGpuStreams.sync(); + GPUChkErrS(cudaMemcpy(mTrackletsLUTDeviceArray, mTrackletsLUTDevice.data(), (NLayers - 1) * sizeof(int*), cudaMemcpyHostToDevice)); +} + +template +void TimeFrameGPU::createNeighboursIndexTablesDevice(const int layer) +{ + GPUTimer timer(mGpuStreams[layer], "creating cells neighbours", layer); + GPULog("gpu-transfer: reserving neighbours LUT for {} elements on layer {}, for {:.2f} MB.", mNCells[layer] + 1, layer, (mNCells[layer] + 1) * sizeof(int) / constants::MB); + allocMemAsync(reinterpret_cast(&mNeighboursIndexTablesDevice[layer]), (mNCells[layer] + 1) * sizeof(int), mGpuStreams[layer], this->hasFrameworkAllocator(), (o2::gpu::GPUMemoryResource::MEMORY_GPU | o2::gpu::GPUMemoryResource::MEMORY_STACK)); + GPUChkErrS(cudaMemsetAsync(mNeighboursIndexTablesDevice[layer], 0, (mNCells[layer] + 1) * sizeof(int), mGpuStreams[layer].get())); } -template -void TimeFrameGPU::createNeighboursLUTDevice(const int layer, const unsigned int nCells) +template +void TimeFrameGPU::createNeighboursLUTDevice(const int layer, const unsigned int nCells) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "reserving neighboursLUT"); - LOGP(debug, "gpu-allocation: reserving neighbours LUT for {} elements on layer {} , for {} MB.", nCells + 1, layer, (nCells + 1) * sizeof(int) / MB); - allocMemAsync(reinterpret_cast(&mNeighboursLUTDevice[layer]), (nCells + 1) * sizeof(int), nullptr, getExtAllocator()); // We need one element more to move exc -> inc - GPUChkErrS(cudaMemsetAsync(mNeighboursLUTDevice[layer], 0, (nCells + 1) * sizeof(int), mGpuStreams[0]->get())); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); + GPUTimer timer(mGpuStreams[layer], "reserving neighboursLUT"); + GPULog("gpu-allocation: reserving neighbours LUT for {} elements on layer {} , for {:.2f} MB.", nCells + 1, layer, (nCells + 1) * sizeof(int) / constants::MB); + allocMemAsync(reinterpret_cast(&mNeighboursLUTDevice[layer]), (nCells + 1) * sizeof(int), mGpuStreams[layer], this->hasFrameworkAllocator(), (o2::gpu::GPUMemoryResource::MEMORY_GPU | o2::gpu::GPUMemoryResource::MEMORY_STACK)); // We need one element more to move exc -> inc + GPUChkErrS(cudaMemsetAsync(mNeighboursLUTDevice[layer], 0, (nCells + 1) * sizeof(int), mGpuStreams[layer].get())); + GPUChkErrS(cudaMemcpyAsync(&mNeighboursCellLUTDeviceArray[layer], &mNeighboursLUTDevice[layer], sizeof(int*), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); } -template -void TimeFrameGPU::loadCellsDevice() +template +void TimeFrameGPU::loadCellsDevice() { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "loading cell seeds"); - for (auto iLayer{0}; iLayer < nLayers - 2; ++iLayer) { - LOGP(debug, "gpu-transfer: loading {} cell seeds on layer {}, for {} MB.", mCells[iLayer].size(), iLayer, mCells[iLayer].size() * sizeof(CellSeed) / MB); - allocMemAsync(reinterpret_cast(&mCellsDevice[iLayer]), mCells[iLayer].size() * sizeof(CellSeed), nullptr, getExtAllocator()); - allocMemAsync(reinterpret_cast(&mNeighboursIndexTablesDevice[iLayer]), (mCells[iLayer].size() + 1) * sizeof(int), nullptr, getExtAllocator()); // accessory for the neigh. finding. - GPUChkErrS(cudaMemsetAsync(mNeighboursIndexTablesDevice[iLayer], 0, (mCells[iLayer].size() + 1) * sizeof(int), mGpuStreams[0]->get())); - GPUChkErrS(cudaMemcpyAsync(mCellsDevice[iLayer], mCells[iLayer].data(), mCells[iLayer].size() * sizeof(CellSeed), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); + GPUTimer timer(mGpuStreams, "loading cell seeds", NLayers - 2); + for (auto iLayer{0}; iLayer < NLayers - 2; ++iLayer) { + GPULog("gpu-transfer: loading {} cell seeds on layer {}, for {:.2f} MB.", this->mCells[iLayer].size(), iLayer, this->mCells[iLayer].size() * sizeof(CellSeed) / constants::MB); + allocMemAsync(reinterpret_cast(&mCellsDevice[iLayer]), this->mCells[iLayer].size() * sizeof(CellSeed), mGpuStreams[iLayer], this->hasFrameworkAllocator()); + allocMemAsync(reinterpret_cast(&mNeighboursIndexTablesDevice[iLayer]), (this->mCells[iLayer].size() + 1) * sizeof(int), mGpuStreams[iLayer], this->hasFrameworkAllocator()); // accessory for the neigh. finding. + GPUChkErrS(cudaMemsetAsync(mNeighboursIndexTablesDevice[iLayer], 0, (this->mCells[iLayer].size() + 1) * sizeof(int), mGpuStreams[iLayer].get())); + GPUChkErrS(cudaMemcpyAsync(mCellsDevice[iLayer], this->mCells[iLayer].data(), this->mCells[iLayer].size() * sizeof(CellSeed), cudaMemcpyHostToDevice, mGpuStreams[iLayer].get())); } - allocMemAsync(reinterpret_cast(&mCellsDeviceArray), (nLayers - 2) * sizeof(CellSeed*), nullptr, getExtAllocator()); - GPUChkErrS(cudaMemcpyAsync(mCellsDeviceArray, mCellsDevice.data(), (nLayers - 2) * sizeof(CellSeed*), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); } -template -void TimeFrameGPU::createCellsLUTDevice() +template +void TimeFrameGPU::createCellsLUTDeviceArray() { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "creating cells LUTs"); - for (auto iLayer{0}; iLayer < nLayers - 2; ++iLayer) { - LOGP(debug, "gpu-transfer: creating cell LUT for {} elements on layer {}, for {} MB.", mNTracklets[iLayer] + 1, iLayer, (mNTracklets[iLayer] + 1) * sizeof(int) / MB); - allocMemAsync(reinterpret_cast(&mCellsLUTDevice[iLayer]), (mNTracklets[iLayer] + 1) * sizeof(int), nullptr, getExtAllocator()); - GPUChkErrS(cudaMemsetAsync(mCellsLUTDevice[iLayer], 0, (mNTracklets[iLayer] + 1) * sizeof(int), mGpuStreams[0]->get())); + { + GPUTimer timer("creating cells LUTs array"); + allocMem(reinterpret_cast(&mCellsLUTDeviceArray), MaxCells * sizeof(int*), this->hasFrameworkAllocator()); + allocMem(reinterpret_cast(&mNeighboursCellLUTDeviceArray), MaxCells * sizeof(int*), this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemset(mNeighboursCellLUTDeviceArray, 0, MaxCells * sizeof(int*))); } - allocMemAsync(reinterpret_cast(&mCellsLUTDeviceArray), (nLayers - 2) * sizeof(int*), nullptr, getExtAllocator()); - GPUChkErrS(cudaMemcpyAsync(mCellsLUTDeviceArray, mCellsLUTDevice.data(), mCellsLUTDevice.size() * sizeof(int*), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); } -template -void TimeFrameGPU::createCellsBuffers(const int layer) +template +void TimeFrameGPU::createCellsLUTDevice(const int layer) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "creating cells buffers"); + GPUTimer timer(mGpuStreams[layer], "creating cells LUTs", layer); + const int firstTransition = this->mTrackingTopologyView.getCell(layer).firstTransition; + GPULog("gpu-transfer: creating cell LUT for {} elements on layer {}, for {:.2f} MB.", mNTracklets[firstTransition] + 1, layer, (mNTracklets[firstTransition] + 1) * sizeof(int) / constants::MB); + allocMemAsync(reinterpret_cast(&mCellsLUTDevice[layer]), (mNTracklets[firstTransition] + 1) * sizeof(int), mGpuStreams[layer], this->hasFrameworkAllocator(), (o2::gpu::GPUMemoryResource::MEMORY_GPU | o2::gpu::GPUMemoryResource::MEMORY_STACK)); + GPUChkErrS(cudaMemsetAsync(mCellsLUTDevice[layer], 0, (mNTracklets[firstTransition] + 1) * sizeof(int), mGpuStreams[layer].get())); + GPUChkErrS(cudaMemcpyAsync(&mCellsLUTDeviceArray[layer], &mCellsLUTDevice[layer], sizeof(int*), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); +} + +template +void TimeFrameGPU::createCellsBuffersArray() +{ + { + GPUTimer timer("creating cells buffers array"); + allocMem(reinterpret_cast(&mCellsDeviceArray), MaxCells * sizeof(CellSeed*), this->hasFrameworkAllocator()); + allocMem(reinterpret_cast(&mNeighboursDeviceArray), MaxCells * sizeof(CellNeighbour*), this->hasFrameworkAllocator()); + GPUChkErrS(cudaMemset(mNeighboursDeviceArray, 0, MaxCells * sizeof(CellNeighbour*))); + GPUChkErrS(cudaMemcpy(mCellsDeviceArray, mCellsDevice.data(), mCellsDevice.size() * sizeof(CellSeed*), cudaMemcpyHostToDevice)); + } +} + +template +void TimeFrameGPU::createCellsBuffers(const int layer) +{ + GPUTimer timer(mGpuStreams[layer], "creating cells buffers"); mNCells[layer] = 0; - GPUChkErrS(cudaMemcpyAsync(&mNCells[layer], mCellsLUTDevice[layer] + mNTracklets[layer], sizeof(int), cudaMemcpyDeviceToHost)); - LOGP(debug, "gpu-transfer: creating cell buffer for {} elements on layer {}, for {} MB.", mNCells[layer], layer, mNCells[layer] * sizeof(CellSeed) / MB); - allocMemAsync(reinterpret_cast(&mCellsDevice[layer]), mNCells[layer] * sizeof(CellSeed), nullptr, getExtAllocator()); + const int firstTransition = this->mTrackingTopologyView.getCell(layer).firstTransition; + GPUChkErrS(cudaMemcpyAsync(&mNCells[layer], mCellsLUTDevice[layer] + mNTracklets[firstTransition], sizeof(int), cudaMemcpyDeviceToHost, mGpuStreams[layer].get())); + mGpuStreams[layer].sync(); // ensure number of cells is correct + GPULog("gpu-transfer: creating cell buffer for {} elements on layer {}, for {:.2f} MB.", mNCells[layer], layer, mNCells[layer] * sizeof(CellSeed) / constants::MB); + allocMemAsync(reinterpret_cast(&mCellsDevice[layer]), mNCells[layer] * sizeof(CellSeed), mGpuStreams[layer], this->hasFrameworkAllocator(), (o2::gpu::GPUMemoryResource::MEMORY_GPU | o2::gpu::GPUMemoryResource::MEMORY_STACK)); + GPUChkErrS(cudaMemsetAsync(mCellsDevice[layer], 0, mNCells[layer] * sizeof(CellSeed), mGpuStreams[layer].get())); + GPUChkErrS(cudaMemcpyAsync(&mCellsDeviceArray[layer], &mCellsDevice[layer], sizeof(CellSeed*), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); +} + +template +void TimeFrameGPU::loadCellsLUTDevice() +{ + GPUTimer timer(mGpuStreams, "loading cells LUTs", NLayers - 3); + for (auto iLayer{0}; iLayer < NLayers - 3; ++iLayer) { + GPULog("gpu-transfer: loading cell LUT for {} elements on layer {}, for {:.2f} MB.", this->mCellsLookupTable[iLayer].size(), iLayer, this->mCellsLookupTable[iLayer].size() * sizeof(int) / constants::MB); + GPUChkErrS(cudaHostRegister(this->mCellsLookupTable[iLayer].data(), this->mCellsLookupTable[iLayer].size() * sizeof(int), cudaHostRegisterPortable)); + GPUChkErrS(cudaMemcpyAsync(mCellsLUTDevice[iLayer + 1], this->mCellsLookupTable[iLayer].data(), this->mCellsLookupTable[iLayer].size() * sizeof(int), cudaMemcpyHostToDevice, mGpuStreams[iLayer].get())); + } +} - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); +template +void TimeFrameGPU::loadTrackSeedsDevice(bounded_vector& seeds) +{ + GPUTimer timer("loading track seeds"); + GPULog("gpu-transfer: loading {} track seeds, for {:.2f} MB.", seeds.size(), seeds.size() * sizeof(TrackSeedN) / constants::MB); + allocMem(reinterpret_cast(&mTrackSeedsDevice), seeds.size() * sizeof(TrackSeedN), this->hasFrameworkAllocator(), (o2::gpu::GPUMemoryResource::MEMORY_GPU | o2::gpu::GPUMemoryResource::MEMORY_STACK)); + GPUChkErrS(cudaMemcpy(mTrackSeedsDevice, seeds.data(), seeds.size() * sizeof(TrackSeedN), cudaMemcpyHostToDevice)); + GPULog("gpu-transfer: creating {} track seeds LUT, for {:.2f} MB.", seeds.size() + 1, (seeds.size() + 1) * sizeof(int) / constants::MB); + allocMem(reinterpret_cast(&mTrackSeedsLUTDevice), (seeds.size() + 1) * sizeof(int), this->hasFrameworkAllocator(), (o2::gpu::GPUMemoryResource::MEMORY_GPU | o2::gpu::GPUMemoryResource::MEMORY_STACK)); + GPUChkErrS(cudaMemset(mTrackSeedsLUTDevice, 0, (seeds.size() + 1) * sizeof(int))); } -template -void TimeFrameGPU::loadCellsLUTDevice() +template +void TimeFrameGPU::createNeighboursDevice(const unsigned int layer) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "loading cells LUTs"); - for (auto iLayer{0}; iLayer < nLayers - 3; ++iLayer) { - LOGP(debug, "gpu-transfer: loading cell LUT for {} elements on layer {}, for {} MB.", mCellsLookupTable[iLayer].size(), iLayer, mCellsLookupTable[iLayer].size() * sizeof(int) / MB); - GPUChkErrS(cudaHostRegister(mCellsLookupTable[iLayer].data(), mCellsLookupTable[iLayer].size() * sizeof(int), cudaHostRegisterPortable)); - GPUChkErrS(cudaMemcpyAsync(mCellsLUTDevice[iLayer + 1], mCellsLookupTable[iLayer].data(), mCellsLookupTable[iLayer].size() * sizeof(int), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); + GPUTimer timer(mGpuStreams[layer], "reserving neighbours", layer); + this->mNNeighbours[layer] = 0; + if (this->mNCells[layer] == 0) { + mNeighboursDevice[layer] = nullptr; + GPUChkErrS(cudaMemcpyAsync(&mNeighboursDeviceArray[layer], &mNeighboursDevice[layer], sizeof(CellNeighbour*), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); + return; + } + GPUChkErrS(cudaMemcpyAsync(&(this->mNNeighbours[layer]), &(mNeighboursLUTDevice[layer][this->mNCells[layer]]), sizeof(unsigned int), cudaMemcpyDeviceToHost, mGpuStreams[layer].get())); + mGpuStreams[layer].sync(); // ensure number of neighbours is correct + if (this->mNNeighbours[layer] == 0) { + mNeighboursDevice[layer] = nullptr; + GPUChkErrS(cudaMemcpyAsync(&mNeighboursDeviceArray[layer], &mNeighboursDevice[layer], sizeof(CellNeighbour*), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); + return; } - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); + GPULog("gpu-allocation: reserving {} neighbours, for {:.2f} MB.", this->mNNeighbours[layer], (this->mNNeighbours[layer]) * sizeof(CellNeighbour) / constants::MB); + allocMemAsync(reinterpret_cast(&mNeighboursDevice[layer]), (this->mNNeighbours[layer]) * sizeof(CellNeighbour), mGpuStreams[layer], this->hasFrameworkAllocator(), (o2::gpu::GPUMemoryResource::MEMORY_GPU | o2::gpu::GPUMemoryResource::MEMORY_STACK)); + GPUChkErrS(cudaMemsetAsync(mNeighboursDevice[layer], -1, (this->mNNeighbours[layer]) * sizeof(CellNeighbour), mGpuStreams[layer].get())); + GPUChkErrS(cudaMemcpyAsync(&mNeighboursDeviceArray[layer], &mNeighboursDevice[layer], sizeof(CellNeighbour*), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); } -template -void TimeFrameGPU::loadRoadsDevice() +template +void TimeFrameGPU::createTrackITSExtDevice(const size_t nSeeds) { - LOGP(debug, "gpu-transfer: loading {} roads, for {} MB.", mRoads.size(), mRoads.size() * sizeof(Road) / MB); - allocMemAsync(reinterpret_cast(&mRoadsDevice), mRoads.size() * sizeof(Road), mGpuStreams[0], getExtAllocator()); - GPUChkErrS(cudaHostRegister(mRoads.data(), mRoads.size() * sizeof(Road), cudaHostRegisterPortable)); - GPUChkErrS(cudaMemcpyAsync(mRoadsDevice, mRoads.data(), mRoads.size() * sizeof(Road), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); + GPUTimer timer("reserving tracks"); + mNTracks = 0; + GPUChkErrS(cudaMemcpy(&mNTracks, mTrackSeedsLUTDevice + nSeeds, sizeof(int), cudaMemcpyDeviceToHost)); + GPULog("gpu-allocation: reserving {} tracks, for {:.2f} MB.", mNTracks, mNTracks * sizeof(o2::its::TrackITSExt) / constants::MB); + mTrackITSExt = bounded_vector(mNTracks, {}, this->getMemoryPool().get()); + allocMem(reinterpret_cast(&mTrackITSExtDevice), mNTracks * sizeof(o2::its::TrackITSExt), this->hasFrameworkAllocator(), (o2::gpu::GPUMemoryResource::MEMORY_GPU | o2::gpu::GPUMemoryResource::MEMORY_STACK)); + GPUChkErrS(cudaMemset(mTrackITSExtDevice, 0, mNTracks * sizeof(o2::its::TrackITSExt))); } -template -void TimeFrameGPU::loadTrackSeedsDevice(std::vector& seeds) +template +void TimeFrameGPU::downloadCellsDevice() { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "loading track seeds"); - LOGP(debug, "gpu-transfer: loading {} track seeds, for {} MB.", seeds.size(), seeds.size() * sizeof(CellSeed) / MB); - allocMemAsync(reinterpret_cast(&mTrackSeedsDevice), seeds.size() * sizeof(CellSeed), mGpuStreams[0], getExtAllocator()); - GPUChkErrS(cudaHostRegister(seeds.data(), seeds.size() * sizeof(CellSeed), cudaHostRegisterPortable)); - GPUChkErrS(cudaMemcpyAsync(mTrackSeedsDevice, seeds.data(), seeds.size() * sizeof(CellSeed), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); + GPUTimer timer(mGpuStreams, "downloading cells", NLayers - 2); + for (int iLayer{0}; iLayer < NLayers - 2; ++iLayer) { + GPULog("gpu-transfer: downloading {} cells on layer: {}, for {:.2f} MB.", mNCells[iLayer], iLayer, mNCells[iLayer] * sizeof(CellSeed) / constants::MB); + this->mCells[iLayer].resize(mNCells[iLayer]); + GPUChkErrS(cudaMemcpyAsync(this->mCells[iLayer].data(), this->mCellsDevice[iLayer], mNCells[iLayer] * sizeof(CellSeed), cudaMemcpyDeviceToHost, mGpuStreams[iLayer].get())); + } } -template -void TimeFrameGPU::createNeighboursDevice(const unsigned int layer, const unsigned int nNeighbours) +template +void TimeFrameGPU::downloadCellsLUTDevice() { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "reserving neighbours"); - LOGP(debug, "gpu-allocation: reserving {} neighbours (pairs), for {} MB.", nNeighbours, nNeighbours * sizeof(gpuPair) / MB); - allocMemAsync(reinterpret_cast(&mNeighbourPairsDevice[layer]), nNeighbours * sizeof(gpuPair), mGpuStreams[0], getExtAllocator()); - GPUChkErrS(cudaMemsetAsync(mNeighbourPairsDevice[layer], -1, nNeighbours * sizeof(gpuPair), mGpuStreams[0]->get())); - LOGP(debug, "gpu-allocation: reserving {} neighbours, for {} MB.", nNeighbours, nNeighbours * sizeof(gpuPair) / MB); - allocMemAsync(reinterpret_cast(&mNeighboursDevice[layer]), nNeighbours * sizeof(int), mGpuStreams[0], getExtAllocator()); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); + GPUTimer timer(mGpuStreams, "downloading cell luts", NLayers - 3); + for (auto iLayer{0}; iLayer < NLayers - 3; ++iLayer) { + GPULog("gpu-transfer: downloading cells lut on layer {} for {} elements", iLayer, (mNTracklets[iLayer + 1] + 1)); + this->mCellsLookupTable[iLayer].resize(mNTracklets[iLayer + 1] + 1); + GPUChkErrS(cudaMemcpyAsync(this->mCellsLookupTable[iLayer].data(), mCellsLUTDevice[iLayer + 1], (mNTracklets[iLayer + 1] + 1) * sizeof(int), cudaMemcpyDeviceToHost, mGpuStreams[iLayer].get())); + } } -template -void TimeFrameGPU::createNeighboursDevice(const unsigned int layer, std::vector>& neighbours) +template +void TimeFrameGPU::downloadCellsNeighboursDevice(std::vector>& neighbours, const int layer) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "reserving neighbours"); - mCellsNeighbours[layer].clear(); - mCellsNeighbours[layer].resize(neighbours.size()); - LOGP(debug, "gpu-allocation: reserving {} neighbours (pairs), for {} MB.", neighbours.size(), neighbours.size() * sizeof(gpuPair) / MB); - allocMemAsync(reinterpret_cast(&mNeighbourPairsDevice[layer]), neighbours.size() * sizeof(gpuPair), mGpuStreams[0], getExtAllocator()); - GPUChkErrS(cudaMemsetAsync(mNeighbourPairsDevice[layer], -1, neighbours.size() * sizeof(gpuPair), mGpuStreams[0]->get())); - LOGP(debug, "gpu-allocation: reserving {} neighbours, for {} MB.", neighbours.size(), neighbours.size() * sizeof(gpuPair) / MB); - allocMemAsync(reinterpret_cast(&mNeighboursDevice[layer]), neighbours.size() * sizeof(int), mGpuStreams[0], getExtAllocator()); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); + GPUTimer timer(mGpuStreams[layer], "downloading neighbours from layer", layer); + GPULog("gpu-transfer: downloading {} neighbours, for {:.2f} MB.", neighbours[layer].size(), neighbours[layer].size() * sizeof(CellNeighbour) / constants::MB); + GPUChkErrS(cudaMemcpyAsync(neighbours[layer].data(), mNeighboursDevice[layer], neighbours[layer].size() * sizeof(CellNeighbour), cudaMemcpyDeviceToHost, mGpuStreams[layer].get())); } -template -void TimeFrameGPU::createNeighboursDeviceArray() +template +void TimeFrameGPU::downloadNeighboursLUTDevice(bounded_vector& lut, const int layer) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "reserving neighbours"); - allocMemAsync(reinterpret_cast(&mNeighboursDeviceArray), (nLayers - 2) * sizeof(int*), mGpuStreams[0], getExtAllocator()); - GPUChkErrS(cudaMemcpyAsync(mNeighboursDeviceArray, mNeighboursDevice.data(), (nLayers - 2) * sizeof(int*), cudaMemcpyHostToDevice, mGpuStreams[0]->get())); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); + GPUTimer timer(mGpuStreams[layer], "downloading neighbours LUT from layer", layer); + GPULog("gpu-transfer: downloading neighbours LUT for {} elements on layer {}, for {:.2f} MB.", lut.size(), layer, lut.size() * sizeof(int) / constants::MB); + GPUChkErrS(cudaMemcpyAsync(lut.data(), mNeighboursLUTDevice[layer], lut.size() * sizeof(int), cudaMemcpyDeviceToHost, mGpuStreams[layer].get())); } -template -void TimeFrameGPU::createTrackITSExtDevice(std::vector& seeds) +template +void TimeFrameGPU::downloadTrackITSExtDevice() { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "reserving tracks"); - mTrackITSExt.clear(); - mTrackITSExt.resize(seeds.size()); - LOGP(debug, "gpu-allocation: reserving {} tracks, for {} MB.", seeds.size(), seeds.size() * sizeof(o2::its::TrackITSExt) / MB); - allocMemAsync(reinterpret_cast(&mTrackITSExtDevice), seeds.size() * sizeof(o2::its::TrackITSExt), mGpuStreams[0], getExtAllocator()); - GPUChkErrS(cudaMemsetAsync(mTrackITSExtDevice, 0, seeds.size() * sizeof(o2::its::TrackITSExt), mGpuStreams[0]->get())); - GPUChkErrS(cudaHostRegister(mTrackITSExt.data(), seeds.size() * sizeof(o2::its::TrackITSExt), cudaHostRegisterPortable)); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); + GPUTimer timer("downloading tracks"); + GPULog("gpu-transfer: downloading {} tracks, for {:.2f} MB.", mTrackITSExt.size(), mTrackITSExt.size() * sizeof(o2::its::TrackITSExt) / constants::MB); + GPUChkErrS(cudaMemcpy(mTrackITSExt.data(), mTrackITSExtDevice, mTrackITSExt.size() * sizeof(o2::its::TrackITSExt), cudaMemcpyDeviceToHost)); } -template -void TimeFrameGPU::downloadCellsDevice() +template +void TimeFrameGPU::unregisterHostMemory(const int maxLayers) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "downloading cells"); - for (int iLayer{0}; iLayer < nLayers - 2; ++iLayer) { - LOGP(debug, "gpu-transfer: downloading {} cells on layer: {}, for {} MB.", mNCells[iLayer], iLayer, mNCells[iLayer] * sizeof(CellSeed) / MB); - mCells[iLayer].resize(mNCells[iLayer]); - GPUChkErrS(cudaMemcpyAsync(mCells[iLayer].data(), mCellsDevice[iLayer], mNCells[iLayer] * sizeof(CellSeed), cudaMemcpyDeviceToHost, mGpuStreams[0]->get())); + GPUTimer timer("unregistering host memory"); + GPULog("unregistering host memory"); + + auto checkedUnregisterEntry = [](auto& bits, auto& vec, int layer) { + if (bits.test(layer)) { + GPUChkErrS(cudaHostUnregister(vec[layer].data())); + bits.reset(layer); + } + }; + auto checkedUnregisterArray = [](auto& bits, auto& vec) { + if (bits.test(NLayers)) { + GPUChkErrS(cudaHostUnregister(vec.data())); + bits.reset(NLayers); + } + }; + + for (auto iLayer{0}; iLayer < NLayers; ++iLayer) { + checkedUnregisterEntry(mPinnedUsedClusters, this->mUsedClusters, iLayer); + checkedUnregisterEntry(mPinnedUnsortedClusters, this->mUnsortedClusters, iLayer); + checkedUnregisterEntry(mPinnedClusters, this->mClusters, iLayer); + checkedUnregisterEntry(mPinnedClustersIndexTables, this->mIndexTables, iLayer); + checkedUnregisterEntry(mPinnedTrackingFrameInfo, this->mTrackingFrameInfo, iLayer); + checkedUnregisterEntry(mPinnedROFramesClusters, this->mROFramesClusters, iLayer); } - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); + checkedUnregisterArray(mPinnedUsedClusters, mUsedClustersDevice); + checkedUnregisterArray(mPinnedUnsortedClusters, mUnsortedClustersDevice); + checkedUnregisterArray(mPinnedClusters, mClustersDevice); + checkedUnregisterArray(mPinnedClustersIndexTables, mClustersIndexTablesDevice); + checkedUnregisterArray(mPinnedTrackingFrameInfo, mTrackingFrameInfoDevice); + checkedUnregisterArray(mPinnedROFramesClusters, mROFramesClustersDevice); +} + +namespace detail +{ +template +constexpr uint64_t makeIterTag() +{ + static_assert(I < 10); + constexpr char tag[] = {'I', 'T', 'S', 'I', 'T', 'E', 'R', char('0' + I), '\0'}; + return qStr2Tag(tag); +} +template +constexpr auto makeIterTags(std::index_sequence) +{ + return std::array{makeIterTag()...}; } +constexpr auto kIterTags = makeIterTags(std::make_index_sequence{}); +} // namespace detail -template -void TimeFrameGPU::downloadCellsLUTDevice() +template +void TimeFrameGPU::pushMemoryStack(const int iteration) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "downloading cell luts"); - for (auto iLayer{0}; iLayer < nLayers - 3; ++iLayer) { - LOGP(debug, "gpu-transfer: downloading cells lut on layer {} for {} elements", iLayer, (mNTracklets[iLayer + 1] + 1)); - mCellsLookupTable[iLayer].resize(mNTracklets[iLayer + 1] + 1); - GPUChkErrS(cudaMemcpyAsync(mCellsLookupTable[iLayer].data(), mCellsLUTDevice[iLayer + 1], (mNTracklets[iLayer + 1] + 1) * sizeof(int), cudaMemcpyDeviceToHost, mGpuStreams[0]->get())); + // mark the beginning of memory marked with MEMORY_STACK that can be discarded + // after doing one iteration + (this->mExternalAllocator)->pushTagOnStack(detail::kIterTags[iteration]); +} + +template +void TimeFrameGPU::popMemoryStack(const int iteration) +{ + // pop all memory on the stack from this iteration + (this->mExternalAllocator)->popTagOffStack(detail::kIterTags[iteration]); +} + +template +void TimeFrameGPU::initialise(const TrackingParameters& trkParam, int maxLayers) +{ + mGpuStreams.resize(MaxStreams); + o2::its::TimeFrame::initialise(trkParam, maxLayers); +} + +template +void TimeFrameGPU::initialise(const TrackingParameters& trkParam, int maxLayers, int iteration) +{ + mGpuStreams.resize(MaxStreams); + o2::its::TimeFrame::initialise(trkParam, maxLayers, iteration); + if (iteration != constants::UnusedIndex && iteration < static_cast(mDeviceTrackerTopologyViews.size())) { + mDeviceTrackingTopologyView = mDeviceTrackerTopologyViews[iteration]; } - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); } -template -void TimeFrameGPU::downloadCellsNeighboursDevice(std::vector>>& neighbours, const int layer) +template +void TimeFrameGPU::syncStream(const size_t stream) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), fmt::format("downloading neighbours from layer {}", layer)); - LOGP(debug, "gpu-transfer: downloading {} neighbours, for {} MB.", neighbours[layer].size(), neighbours[layer].size() * sizeof(std::pair) / MB); - // TODO: something less dangerous than assuming the same memory layout of std::pair and gpuPair... or not? :) - GPUChkErrS(cudaMemcpyAsync(neighbours[layer].data(), mNeighbourPairsDevice[layer], neighbours[layer].size() * sizeof(gpuPair), cudaMemcpyDeviceToHost, mGpuStreams[0]->get())); + mGpuStreams[stream].sync(); } -template -void TimeFrameGPU::downloadNeighboursLUTDevice(std::vector& lut, const int layer) +template +void TimeFrameGPU::syncStreams(const bool device) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), fmt::format("downloading neighbours LUT from layer {}", layer)); - LOGP(debug, "gpu-transfer: downloading neighbours LUT for {} elements on layer {}, for {} MB.", lut.size(), layer, lut.size() * sizeof(int) / MB); - GPUChkErrS(cudaMemcpyAsync(lut.data(), mNeighboursLUTDevice[layer], lut.size() * sizeof(int), cudaMemcpyDeviceToHost, mGpuStreams[0]->get())); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); + mGpuStreams.sync(device); } -template -void TimeFrameGPU::downloadTrackITSExtDevice(std::vector& seeds) +template +void TimeFrameGPU::waitEvent(const int stream, const int event) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "downloading tracks"); - LOGP(debug, "gpu-transfer: downloading {} tracks, for {} MB.", mTrackITSExt.size(), mTrackITSExt.size() * sizeof(o2::its::TrackITSExt) / MB); - GPUChkErrS(cudaMemcpyAsync(mTrackITSExt.data(), mTrackITSExtDevice, seeds.size() * sizeof(o2::its::TrackITSExt), cudaMemcpyDeviceToHost, mGpuStreams[0]->get())); - GPUChkErrS(cudaHostUnregister(mTrackITSExt.data())); - GPUChkErrS(cudaHostUnregister(seeds.data())); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); + mGpuStreams.waitEvent(stream, event); } -template -void TimeFrameGPU::unregisterRest() +template +void TimeFrameGPU::recordEvent(const int event) { - START_GPU_STREAM_TIMER(mGpuStreams[0]->get(), "unregistering rest of the host memory"); - LOGP(debug, "unregistering rest of the host memory..."); - GPUChkErrS(cudaHostUnregister(mCellsDevice.data())); - GPUChkErrS(cudaHostUnregister(mTrackletsDevice.data())); - STOP_GPU_STREAM_TIMER(mGpuStreams[0]->get()); + mGpuStreams[event].record(); } -template -void TimeFrameGPU::unregisterHostMemory(const int maxLayers) +template +void TimeFrameGPU::recordEvents(const int start, const int end) { - for (auto iLayer{0}; iLayer < nLayers; ++iLayer) { - GPUChkErrS(cudaHostUnregister(mUnsortedClusters[iLayer].data())); - GPUChkErrS(cudaHostUnregister(mClusters[iLayer].data())); - GPUChkErrS(cudaHostUnregister(mTrackingFrameInfo[iLayer].data())); + for (int i{start}; i < end; ++i) { + recordEvent(i); } - GPUChkErrS(cudaHostUnregister(mTrackingFrameInfoDevice.data())); - GPUChkErrS(cudaHostUnregister(mUnsortedClustersDevice.data())); - GPUChkErrS(cudaHostUnregister(mClustersDevice.data())); } -template -void TimeFrameGPU::initialise(const int iteration, - const TrackingParameters& trkParam, - const int maxLayers, - IndexTableUtils* utils, - const TimeFrameGPUParameters* gpuParam) +template +void TimeFrameGPU::wipe() { - mGpuStreams.resize(mGpuParams.nTimeFrameChunks); - for (auto& str : mGpuStreams) { - str = new Stream(); - } - o2::its::TimeFrame::initialise(iteration, trkParam, maxLayers); + unregisterHostMemory(0); + o2::its::TimeFrame::wipe(); } template class TimeFrameGPU<7>; -} // namespace gpu -} // namespace its -} // namespace o2 +// ALICE3 upgrade +#ifdef ENABLE_UPGRADES +template class TimeFrameGPU<11>; +#endif +} // namespace o2::its::gpu diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TracerGPU.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TracerGPU.cu deleted file mode 100644 index 7c42658242231..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TracerGPU.cu +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include -#include "ITStrackingGPU/TracerGPU.h" - -#if !defined(__HIPCC__) && defined(__USE_GPU_TRACER__) -#include - -constexpr uint32_t colors[] = {0xff00ff00, 0xff0000ff, 0xffffff00, 0xffff00ff, 0xff00ffff, 0xffff0000, 0xffffffff}; -constexpr int num_colors = sizeof(colors) / sizeof(uint32_t); - -namespace o2 -{ -namespace its -{ -namespace gpu -{ -Tracer::Tracer(const char* name, int color_id) -{ - color_id = color_id % num_colors; - nvtxEventAttributes_t eventAttrib = {0}; - eventAttrib.version = NVTX_VERSION; - eventAttrib.size = NVTX_EVENT_ATTRIB_STRUCT_SIZE; - eventAttrib.colorType = NVTX_COLOR_ARGB; - eventAttrib.color = colors[color_id]; - eventAttrib.messageType = NVTX_MESSAGE_TYPE_ASCII; - eventAttrib.message.ascii = name; - nvtxRangePushEx(&eventAttrib); -} - -Tracer::~Tracer() -{ - nvtxRangePop(); -} - -} // namespace gpu -} // namespace its -} // namespace o2 -#endif diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx index f3b62ec8a6108..141d558712e6d 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx @@ -10,332 +10,417 @@ // or submit itself to any jurisdiction. /// -#include #include -#include "DataFormatsITS/TrackITS.h" - #include "ITStrackingGPU/TrackerTraitsGPU.h" #include "ITStrackingGPU/TrackingKernels.h" -#include "ITStracking/TrackingConfigParam.h" +#include "ITStracking/Configuration.h" + namespace o2::its { -constexpr int UnusedIndex{-1}; -template -void TrackerTraitsGPU::initialiseTimeFrame(const int iteration) +template +void TrackerTraitsGPU::initialiseTimeFrame(const int iteration) { - mTimeFrameGPU->initialise(iteration, mTrkParams[iteration], nLayers); - mTimeFrameGPU->loadClustersDevice(iteration); - mTimeFrameGPU->loadUnsortedClustersDevice(iteration); - mTimeFrameGPU->loadClustersIndexTables(iteration); - mTimeFrameGPU->loadTrackingFrameInfoDevice(iteration); - mTimeFrameGPU->loadMultiplicityCutMask(iteration); - mTimeFrameGPU->loadVertices(iteration); - mTimeFrameGPU->loadROframeClustersDevice(iteration); - mTimeFrameGPU->createUsedClustersDevice(iteration); - mTimeFrameGPU->loadIndexTableUtils(iteration); + mTimeFrameGPU->initialise(this->mTrkParams[iteration], NLayers, iteration); + + if (this->mTrkParams[iteration].PassFlags[IterationStep::FirstPass]) { + // on default stream + mTimeFrameGPU->loadVertices(); + // TODO these tables can be put in persistent memory + mTimeFrameGPU->loadROFOverlapTable(); // this can be put in constant memory actually + mTimeFrameGPU->loadROFVertexLookupTable(); + mTimeFrameGPU->loadTrackingTopologies(); + // once the tables are in persistent memory just update the vertex one + // mTimeFrameGPU->updateROFVertexLookupTable(); + mTimeFrameGPU->loadIndexTableUtils(); + // pinned on host + mTimeFrameGPU->createUsedClustersDeviceArray(); + mTimeFrameGPU->createClustersDeviceArray(); + mTimeFrameGPU->createUnsortedClustersDeviceArray(); + mTimeFrameGPU->createClustersIndexTablesArray(); + mTimeFrameGPU->createTrackingFrameInfoDeviceArray(); + mTimeFrameGPU->createROFrameClustersDeviceArray(); + // device array + mTimeFrameGPU->createTrackletsLUTDeviceArray(); + mTimeFrameGPU->createTrackletsBuffersArray(); + mTimeFrameGPU->createCellsBuffersArray(); + mTimeFrameGPU->createCellsLUTDeviceArray(); + } + if (this->mTrkParams[iteration].PassFlags[IterationStep::FirstPass] || this->mTrkParams[iteration].PassFlags[IterationStep::UseUPCMask]) { + mTimeFrameGPU->loadROFCutMask(iteration); + } + // push every create artefact on the stack + mTimeFrameGPU->pushMemoryStack(iteration); } -template -void TrackerTraitsGPU::computeLayerTracklets(const int iteration, int iROFslice, int iVertex) +template +void TrackerTraitsGPU::adoptTimeFrame(TimeFrame* tf) { - auto& conf = o2::its::ITSGpuTrackingParamConfig::Instance(); - mTimeFrameGPU->createTrackletsLUTDevice(iteration); + mTimeFrameGPU = static_cast*>(tf); + this->mTimeFrame = static_cast*>(tf); +} - const Vertex diamondVert({mTrkParams[iteration].Diamond[0], mTrkParams[iteration].Diamond[1], mTrkParams[iteration].Diamond[2]}, {25.e-6f, 0.f, 0.f, 25.e-6f, 0.f, 36.f}, 1, 1.f); - gsl::span diamondSpan(&diamondVert, 1); - int startROF{mTrkParams[iteration].nROFsPerIterations > 0 ? iROFslice * mTrkParams[iteration].nROFsPerIterations : 0}; - int endROF{o2::gpu::CAMath::Min(mTrkParams[iteration].nROFsPerIterations > 0 ? (iROFslice + 1) * mTrkParams[iteration].nROFsPerIterations + mTrkParams[iteration].DeltaROF : mTimeFrameGPU->getNrof(), mTimeFrameGPU->getNrof())}; +template +void TrackerTraitsGPU::computeLayerTracklets(const int iteration, int iVertex) +{ + const auto topology = mTimeFrameGPU->getDeviceTrackingTopologyView(); + const auto hostTopology = mTimeFrameGPU->getTrackingTopologyView(); + for (int iLayer{0}; iLayer < this->mTrkParams[iteration].NLayers; ++iLayer) { + if (this->mTrkParams[iteration].PassFlags[IterationStep::FirstPass]) { + mTimeFrameGPU->createUsedClustersDevice(iLayer); + mTimeFrameGPU->loadClustersDevice(iLayer); + mTimeFrameGPU->loadClustersIndexTables(iLayer); + mTimeFrameGPU->loadROFrameClustersDevice(iLayer); + } + mTimeFrameGPU->recordEvent(iLayer); + } - countTrackletsInROFsHandler(mTimeFrameGPU->getDeviceIndexTableUtils(), - mTimeFrameGPU->getDeviceMultCutMask(), - startROF, - endROF, - mTimeFrameGPU->getNrof(), - mTrkParams[iteration].DeltaROF, - iVertex, - mTimeFrameGPU->getDeviceVertices(), - mTimeFrameGPU->getDeviceROFramesPV(), - mTimeFrameGPU->getPrimaryVerticesNum(), - mTimeFrameGPU->getDeviceArrayClusters(), - mTimeFrameGPU->getClusterSizes(), - mTimeFrameGPU->getDeviceROframeClusters(), - mTimeFrameGPU->getDeviceArrayUsedClusters(), - mTimeFrameGPU->getDeviceArrayClustersIndexTables(), - mTimeFrameGPU->getDeviceArrayTrackletsLUT(), - mTimeFrameGPU->getDeviceTrackletsLUTs(), // Required for the exclusive sums - iteration, - mTrkParams[iteration].NSigmaCut, - mTimeFrameGPU->getPhiCuts(), - mTrkParams[iteration].PVres, - mTimeFrameGPU->getMinRs(), - mTimeFrameGPU->getMaxRs(), - mTimeFrameGPU->getPositionResolutions(), - mTrkParams[iteration].LayerRadii, - mTimeFrameGPU->getMSangles(), - conf.nBlocks, - conf.nThreads); - mTimeFrameGPU->createTrackletsBuffers(); - computeTrackletsInROFsHandler(mTimeFrameGPU->getDeviceIndexTableUtils(), - mTimeFrameGPU->getDeviceMultCutMask(), - startROF, - endROF, - mTimeFrameGPU->getNrof(), - mTrkParams[iteration].DeltaROF, + for (int transitionId{0}; transitionId < hostTopology.nTransitions; ++transitionId) { + const auto transition = hostTopology.getTransition(transitionId); + mTimeFrameGPU->createTrackletsLUTDevice(this->mTrkParams[iteration].PassFlags[IterationStep::FirstPass], transitionId); + mTimeFrameGPU->waitEvent(transitionId, transition.fromLayer); + mTimeFrameGPU->waitEvent(transitionId, transition.toLayer); + countTrackletsInROFsHandler(mTimeFrameGPU->getDeviceIndexTableUtils(), + mTimeFrameGPU->getDeviceROFMaskTableView(), + transitionId, + transition.fromLayer, + transition.toLayer, + mTimeFrameGPU->getDeviceROFOverlapTableView(), + mTimeFrameGPU->getDeviceROFVertexLookupTableView(), iVertex, mTimeFrameGPU->getDeviceVertices(), mTimeFrameGPU->getDeviceROFramesPV(), - mTimeFrameGPU->getPrimaryVerticesNum(), mTimeFrameGPU->getDeviceArrayClusters(), mTimeFrameGPU->getClusterSizes(), - mTimeFrameGPU->getDeviceROframeClusters(), - mTimeFrameGPU->getDeviceArrayUsedClusters(), + mTimeFrameGPU->getDeviceROFrameClusters(), + (const uint8_t**)mTimeFrameGPU->getDeviceArrayUsedClusters(), mTimeFrameGPU->getDeviceArrayClustersIndexTables(), - mTimeFrameGPU->getDeviceArrayTracklets(), - mTimeFrameGPU->getDeviceTracklet(), - mTimeFrameGPU->getNTracklets(), mTimeFrameGPU->getDeviceArrayTrackletsLUT(), mTimeFrameGPU->getDeviceTrackletsLUTs(), - iteration, - mTrkParams[iteration].NSigmaCut, - mTimeFrameGPU->getPhiCuts(), - mTrkParams[iteration].PVres, + this->mTrkParams[iteration].PassFlags[IterationStep::SelectUPCVertices], + this->mTrkParams[iteration].NSigmaCut, + topology, + mTimeFrameGPU->getTransitionPhiCuts(), + this->mTrkParams[iteration].PVres, mTimeFrameGPU->getMinRs(), mTimeFrameGPU->getMaxRs(), mTimeFrameGPU->getPositionResolutions(), - mTrkParams[iteration].LayerRadii, - mTimeFrameGPU->getMSangles(), - conf.nBlocks, - conf.nThreads); + this->mTrkParams[iteration].LayerRadii, + mTimeFrameGPU->getTransitionMSAngles(), + mTimeFrameGPU->getFrameworkAllocator(), + mTimeFrameGPU->getStreams()); + mTimeFrameGPU->createTrackletsBuffers(transitionId); + if (mTimeFrameGPU->getNTracklets()[transitionId] == 0) { + mTimeFrameGPU->recordEvent(transitionId); + continue; + } + computeTrackletsInROFsHandler(mTimeFrameGPU->getDeviceIndexTableUtils(), + mTimeFrameGPU->getDeviceROFMaskTableView(), + transitionId, + transition.fromLayer, + transition.toLayer, + mTimeFrameGPU->getDeviceROFOverlapTableView(), + mTimeFrameGPU->getDeviceROFVertexLookupTableView(), + iVertex, + mTimeFrameGPU->getDeviceVertices(), + mTimeFrameGPU->getDeviceROFramesPV(), + mTimeFrameGPU->getDeviceArrayClusters(), + mTimeFrameGPU->getClusterSizes(), + mTimeFrameGPU->getDeviceROFrameClusters(), + (const uint8_t**)mTimeFrameGPU->getDeviceArrayUsedClusters(), + mTimeFrameGPU->getDeviceArrayClustersIndexTables(), + mTimeFrameGPU->getDeviceArrayTracklets(), + mTimeFrameGPU->getDeviceTracklets(), + mTimeFrameGPU->getNTracklets(), + mTimeFrameGPU->getDeviceArrayTrackletsLUT(), + mTimeFrameGPU->getDeviceTrackletsLUTs(), + this->mTrkParams[iteration].PassFlags[IterationStep::SelectUPCVertices], + this->mTrkParams[iteration].NSigmaCut, + topology, + mTimeFrameGPU->getTransitionPhiCuts(), + this->mTrkParams[iteration].PVres, + mTimeFrameGPU->getMinRs(), + mTimeFrameGPU->getMaxRs(), + mTimeFrameGPU->getPositionResolutions(), + this->mTrkParams[iteration].LayerRadii, + mTimeFrameGPU->getTransitionMSAngles(), + mTimeFrameGPU->getFrameworkAllocator(), + mTimeFrameGPU->getStreams()); + mTimeFrameGPU->recordEvent(transitionId); + } } -template -void TrackerTraitsGPU::computeLayerCells(const int iteration) +template +void TrackerTraitsGPU::computeLayerCells(const int iteration) { - mTimeFrameGPU->createCellsLUTDevice(); - auto& conf = o2::its::ITSGpuTrackingParamConfig::Instance(); + const auto topology = mTimeFrameGPU->getDeviceTrackingTopologyView(); + const auto hostTopology = mTimeFrameGPU->getTrackingTopologyView(); + for (int iLayer{0}; iLayer < this->mTrkParams[iteration].NLayers; ++iLayer) { + if (this->mTrkParams[iteration].PassFlags[IterationStep::FirstPass]) { + mTimeFrameGPU->loadUnsortedClustersDevice(iLayer); + mTimeFrameGPU->loadTrackingFrameInfoDevice(iLayer); + } + mTimeFrameGPU->recordEvent(iLayer); + } - for (int iLayer = 0; iLayer < mTrkParams[iteration].CellsPerRoad(); ++iLayer) { - if (!mTimeFrameGPU->getNTracklets()[iLayer + 1] || !mTimeFrameGPU->getNTracklets()[iLayer]) { + for (int cellTopologyId{hostTopology.nCells}; cellTopologyId--;) { + const auto cellTopology = hostTopology.getCell(cellTopologyId); + const auto first = hostTopology.getTransition(cellTopology.firstTransition); + const auto second = hostTopology.getTransition(cellTopology.secondTransition); + const int currentLayerTrackletsNum{static_cast(mTimeFrameGPU->getNTracklets()[cellTopology.firstTransition])}; + if (!currentLayerTrackletsNum || !mTimeFrameGPU->getNTracklets()[cellTopology.secondTransition]) { + mTimeFrameGPU->getNCells()[cellTopologyId] = 0; continue; } - const int currentLayerTrackletsNum{static_cast(mTimeFrameGPU->getNTracklets()[iLayer])}; - countCellsHandler(mTimeFrameGPU->getDeviceArrayClusters(), - mTimeFrameGPU->getDeviceArrayUnsortedClusters(), - mTimeFrameGPU->getDeviceArrayTrackingFrameInfo(), - mTimeFrameGPU->getDeviceArrayTracklets(), - mTimeFrameGPU->getDeviceArrayTrackletsLUT(), - mTimeFrameGPU->getNTracklets()[iLayer], - iLayer, - nullptr, - mTimeFrameGPU->getDeviceArrayCellsLUT(), - mTimeFrameGPU->getDeviceCellLUTs()[iLayer], - mBz, - mTrkParams[iteration].MaxChi2ClusterAttachment, - mTrkParams[iteration].CellDeltaTanLambdaSigma, - mTrkParams[iteration].NSigmaCut, - conf.nBlocks, - conf.nThreads); - mTimeFrameGPU->createCellsBuffers(iLayer); - computeCellsHandler(mTimeFrameGPU->getDeviceArrayClusters(), - mTimeFrameGPU->getDeviceArrayUnsortedClusters(), - mTimeFrameGPU->getDeviceArrayTrackingFrameInfo(), - mTimeFrameGPU->getDeviceArrayTracklets(), - mTimeFrameGPU->getDeviceArrayTrackletsLUT(), - mTimeFrameGPU->getNTracklets()[iLayer], - iLayer, - mTimeFrameGPU->getDeviceCells()[iLayer], - mTimeFrameGPU->getDeviceArrayCellsLUT(), - mTimeFrameGPU->getDeviceCellLUTs()[iLayer], - mBz, - mTrkParams[iteration].MaxChi2ClusterAttachment, - mTrkParams[iteration].CellDeltaTanLambdaSigma, - mTrkParams[iteration].NSigmaCut, - conf.nBlocks, - conf.nThreads); + + mTimeFrameGPU->createCellsLUTDevice(cellTopologyId); + mTimeFrameGPU->waitEvent(cellTopologyId, cellTopology.firstTransition); + mTimeFrameGPU->waitEvent(cellTopologyId, cellTopology.secondTransition); + mTimeFrameGPU->waitEvent(cellTopologyId, first.fromLayer); + mTimeFrameGPU->waitEvent(cellTopologyId, first.toLayer); + mTimeFrameGPU->waitEvent(cellTopologyId, second.toLayer); + countCellsHandler(mTimeFrameGPU->getDeviceArrayClusters(), + mTimeFrameGPU->getDeviceArrayUnsortedClusters(), + mTimeFrameGPU->getDeviceArrayTrackingFrameInfo(), + mTimeFrameGPU->getDeviceArrayTracklets(), + mTimeFrameGPU->getDeviceArrayTrackletsLUT(), + currentLayerTrackletsNum, + cellTopologyId, + topology, + nullptr, + mTimeFrameGPU->getDeviceArrayCellsLUT(), + mTimeFrameGPU->getDeviceCellLUTs()[cellTopologyId], + this->mBz, + this->mTrkParams[iteration].MaxChi2ClusterAttachment, + this->mTrkParams[iteration].CellDeltaTanLambdaSigma, + this->mTrkParams[iteration].NSigmaCut, + this->mTrkParams[iteration].LayerxX0, + mTimeFrameGPU->getFrameworkAllocator(), + mTimeFrameGPU->getStreams()); + mTimeFrameGPU->createCellsBuffers(cellTopologyId); + if (mTimeFrameGPU->getNCells()[cellTopologyId] == 0) { + mTimeFrameGPU->recordEvent(cellTopologyId); + continue; + } + computeCellsHandler(mTimeFrameGPU->getDeviceArrayClusters(), + mTimeFrameGPU->getDeviceArrayUnsortedClusters(), + mTimeFrameGPU->getDeviceArrayTrackingFrameInfo(), + mTimeFrameGPU->getDeviceArrayTracklets(), + mTimeFrameGPU->getDeviceArrayTrackletsLUT(), + currentLayerTrackletsNum, + cellTopologyId, + topology, + mTimeFrameGPU->getDeviceCells()[cellTopologyId], + mTimeFrameGPU->getDeviceArrayCellsLUT(), + mTimeFrameGPU->getDeviceCellLUTs()[cellTopologyId], + this->mBz, + this->mTrkParams[iteration].MaxChi2ClusterAttachment, + this->mTrkParams[iteration].CellDeltaTanLambdaSigma, + this->mTrkParams[iteration].NSigmaCut, + this->mTrkParams[iteration].LayerxX0, + mTimeFrameGPU->getStreams()); + mTimeFrameGPU->recordEvent(cellTopologyId); } + mTimeFrameGPU->syncStreams(false); } -template -void TrackerTraitsGPU::findCellsNeighbours(const int iteration) +template +void TrackerTraitsGPU::findCellsNeighbours(const int iteration) { - mTimeFrameGPU->createNeighboursIndexTablesDevice(); - auto& conf = o2::its::ITSGpuTrackingParamConfig::Instance(); - for (int iLayer{0}; iLayer < mTrkParams[iteration].CellsPerRoad() - 1; ++iLayer) { - const int nextLayerCellsNum{static_cast(mTimeFrameGPU->getNCells()[iLayer + 1])}; - - if (!nextLayerCellsNum) { - continue; - } + const auto hostTopology = mTimeFrameGPU->getTrackingTopologyView(); + for (int outerLayer{0}; outerLayer < NLayers; ++outerLayer) { + for (int targetCellTopologyId{0}; targetCellTopologyId < hostTopology.nCells; ++targetCellTopologyId) { + const auto targetCellTopology = hostTopology.getCell(targetCellTopologyId); + if (targetCellTopology.hitLayerMask.last() != outerLayer) { + continue; + } + const int targetCellsNum{static_cast(mTimeFrameGPU->getNCells()[targetCellTopologyId])}; + if (!targetCellsNum) { + mTimeFrameGPU->getNNeighbours()[targetCellTopologyId] = 0; + mTimeFrameGPU->recordEvent(targetCellTopologyId); + continue; + } + mTimeFrameGPU->createNeighboursIndexTablesDevice(targetCellTopologyId); + mTimeFrameGPU->createNeighboursLUTDevice(targetCellTopologyId, targetCellsNum); - mTimeFrameGPU->createNeighboursLUTDevice(iLayer, nextLayerCellsNum); - unsigned int nNeigh = countCellNeighboursHandler(mTimeFrameGPU->getDeviceArrayCells(), - mTimeFrameGPU->getDeviceNeighboursLUT(iLayer), // LUT is initialised here. - mTimeFrameGPU->getDeviceArrayCellsLUT(), - mTimeFrameGPU->getDeviceNeighbourPairs(iLayer), - mTimeFrameGPU->getDeviceNeighboursIndexTables(iLayer), - mTrkParams[0].MaxChi2ClusterAttachment, - mBz, - iLayer, - mTimeFrameGPU->getNCells()[iLayer], - nextLayerCellsNum, - 1e2, - conf.nBlocks, - conf.nThreads); + for (int sourceCellTopologyId{0}; sourceCellTopologyId < hostTopology.nCells; ++sourceCellTopologyId) { + const auto sourceCellTopology = hostTopology.getCell(sourceCellTopologyId); + const int sourceCellsNum{static_cast(mTimeFrameGPU->getNCells()[sourceCellTopologyId])}; + if (!sourceCellsNum || sourceCellTopology.secondTransition != targetCellTopology.firstTransition) { + continue; + } + mTimeFrameGPU->waitEvent(targetCellTopologyId, sourceCellTopologyId); + countCellNeighboursHandler(mTimeFrameGPU->getDeviceArrayCells(), + mTimeFrameGPU->getDeviceNeighboursIndexTables(targetCellTopologyId), + mTimeFrameGPU->getDeviceArrayCellsLUT(), + sourceCellTopologyId, + targetCellTopologyId, + this->mTrkParams[iteration].MaxChi2ClusterAttachment, + this->mBz, + sourceCellsNum, + mTimeFrameGPU->getStream(targetCellTopologyId)); + } - mTimeFrameGPU->createNeighboursDevice(iLayer, nNeigh); + scanCellNeighboursHandler(mTimeFrameGPU->getDeviceNeighboursIndexTables(targetCellTopologyId), + mTimeFrameGPU->getDeviceNeighboursLUT(targetCellTopologyId), + targetCellsNum, + mTimeFrameGPU->getFrameworkAllocator(), + mTimeFrameGPU->getStream(targetCellTopologyId)); - computeCellNeighboursHandler(mTimeFrameGPU->getDeviceArrayCells(), - mTimeFrameGPU->getDeviceNeighboursLUT(iLayer), - mTimeFrameGPU->getDeviceArrayCellsLUT(), - mTimeFrameGPU->getDeviceNeighbourPairs(iLayer), - mTimeFrameGPU->getDeviceNeighboursIndexTables(iLayer), - mTrkParams[0].MaxChi2ClusterAttachment, - mBz, - iLayer, - mTimeFrameGPU->getNCells()[iLayer], - nextLayerCellsNum, - 1e2, - conf.nBlocks, - conf.nThreads); + mTimeFrameGPU->createNeighboursDevice(targetCellTopologyId); + if (mTimeFrameGPU->getNNeighbours()[targetCellTopologyId] == 0) { + mTimeFrameGPU->recordEvent(targetCellTopologyId); + continue; + } - filterCellNeighboursHandler(mTimeFrameGPU->getDeviceNeighbourPairs(iLayer), - mTimeFrameGPU->getDeviceNeighbours(iLayer), - nNeigh); + for (int sourceCellTopologyId{0}; sourceCellTopologyId < hostTopology.nCells; ++sourceCellTopologyId) { + const auto sourceCellTopology = hostTopology.getCell(sourceCellTopologyId); + const int sourceCellsNum{static_cast(mTimeFrameGPU->getNCells()[sourceCellTopologyId])}; + if (!sourceCellsNum || sourceCellTopology.secondTransition != targetCellTopology.firstTransition) { + continue; + } + computeCellNeighboursHandler(mTimeFrameGPU->getDeviceArrayCells(), + mTimeFrameGPU->getDeviceNeighboursIndexTables(targetCellTopologyId), + mTimeFrameGPU->getDeviceArrayCellsLUT(), + mTimeFrameGPU->getDeviceNeighbours(targetCellTopologyId), + sourceCellTopologyId, + targetCellTopologyId, + this->mTrkParams[iteration].MaxChi2ClusterAttachment, + this->mBz, + sourceCellsNum, + mTimeFrameGPU->getStream(targetCellTopologyId)); + } + mTimeFrameGPU->recordEvent(targetCellTopologyId); + } } - mTimeFrameGPU->createNeighboursDeviceArray(); - mTimeFrameGPU->unregisterRest(); -}; + mTimeFrameGPU->syncStreams(false); +} -template -void TrackerTraitsGPU::findRoads(const int iteration) +template +void TrackerTraitsGPU::findRoads(const int iteration) { - auto& conf = o2::its::ITSGpuTrackingParamConfig::Instance(); - for (int startLevel{mTrkParams[iteration].CellsPerRoad()}; startLevel >= mTrkParams[iteration].CellMinimumLevel(); --startLevel) { - const int minimumLayer{startLevel - 1}; - std::vector trackSeeds; - for (int startLayer{mTrkParams[iteration].CellsPerRoad() - 1}; startLayer >= minimumLayer; --startLayer) { - if ((mTrkParams[iteration].StartLayerMask & (1 << (startLayer + 2))) == 0) { + bounded_vector> firstClusters(this->mTrkParams[iteration].NLayers, bounded_vector(this->getMemoryPool().get()), this->getMemoryPool().get()); + bounded_vector> sharedFirstClusters(this->mTrkParams[iteration].NLayers, bounded_vector(this->getMemoryPool().get()), this->getMemoryPool().get()); + firstClusters.resize(this->mTrkParams[iteration].NLayers); + sharedFirstClusters.resize(this->mTrkParams[iteration].NLayers); + const auto hostTopology = mTimeFrameGPU->getTrackingTopologyView(); + for (int startLevel{this->mTrkParams[iteration].CellsPerRoad()}; startLevel >= this->mTrkParams[iteration].CellMinimumLevel(); --startLevel) { + bounded_vector> trackSeeds(this->getMemoryPool().get()); + for (int startCellTopologyId{0}; startCellTopologyId < hostTopology.nCells; ++startCellTopologyId) { + const int startLayer = hostTopology.getCell(startCellTopologyId).hitLayerMask.last(); + if (!(this->mTrkParams[iteration].StartLayerMask.has(startLayer)) || mTimeFrameGPU->getNCells()[startCellTopologyId] == 0) { continue; } - processNeighboursHandler(startLayer, - startLevel, + processNeighboursHandler(startLevel, + startCellTopologyId, mTimeFrameGPU->getDeviceArrayCells(), - mTimeFrameGPU->getDeviceCells()[startLayer], - mTimeFrameGPU->getArrayNCells(), - mTimeFrameGPU->getDeviceArrayUsedClusters(), - mTimeFrameGPU->getDeviceNeighboursAll(), - mTimeFrameGPU->getDeviceNeighboursLUTs(), + mTimeFrameGPU->getDeviceCells()[startCellTopologyId], + nullptr, + nullptr, + mTimeFrameGPU->getArrayNCells().data(), + (const uint8_t**)mTimeFrameGPU->getDeviceArrayUsedClusters(), + mTimeFrameGPU->getDeviceArrayNeighbours(), + mTimeFrameGPU->getDeviceArrayNeighboursCellLUT(), mTimeFrameGPU->getDeviceArrayTrackingFrameInfo(), trackSeeds, - mBz, - mTrkParams[0].MaxChi2ClusterAttachment, - mTrkParams[0].MaxChi2NDF, + this->mBz, + this->mTrkParams[iteration].MaxChi2ClusterAttachment, + this->mTrkParams[iteration].MaxChi2NDF, + this->mTrkParams[iteration].MaxHoles, + this->mTrkParams[iteration].MinTrackLength, + this->mTrkParams[iteration].HoleLayerMask, + this->mTrkParams[iteration].LayerxX0, mTimeFrameGPU->getDevicePropagator(), - mCorrType, - conf.nBlocks, - conf.nThreads); + this->mTrkParams[iteration].CorrType, + mTimeFrameGPU->getFrameworkAllocator()); } // fixme: I don't want to move tracks back and forth, but I need a way to use a thrust::allocator that is aware of our managed memory. - if (!trackSeeds.size()) { - LOGP(info, "No track seeds found, skipping track finding"); + if (trackSeeds.empty()) { + LOGP(debug, "No track seeds found, skipping track finding"); continue; } - mTimeFrameGPU->createTrackITSExtDevice(trackSeeds); mTimeFrameGPU->loadTrackSeedsDevice(trackSeeds); - trackSeedHandler(mTimeFrameGPU->getDeviceTrackSeeds(), // CellSeed* trackSeeds - mTimeFrameGPU->getDeviceArrayTrackingFrameInfo(), // TrackingFrameInfo** foundTrackingFrameInfo - mTimeFrameGPU->getDeviceTrackITSExt(), // o2::its::TrackITSExt* tracks - mTrkParams[iteration].MinPt, // std::vector& minPtsHost, - trackSeeds.size(), // const size_t nSeeds - mBz, // const float Bz - startLevel, // const int startLevel, - mTrkParams[0].MaxChi2ClusterAttachment, // float maxChi2ClusterAttachment - mTrkParams[0].MaxChi2NDF, // float maxChi2NDF - mTimeFrameGPU->getDevicePropagator(), // const o2::base::Propagator* propagator - mCorrType, // o2::base::PropagatorImpl::MatCorrType - conf.nBlocks, - conf.nThreads); - - mTimeFrameGPU->downloadTrackITSExtDevice(trackSeeds); + // Since TrackITSExt is an enourmous class it is better to first count how many + // successfull fits we do and only then allocate + countTrackSeedHandler(mTimeFrameGPU->getDeviceTrackSeeds(), + mTimeFrameGPU->getDeviceArrayTrackingFrameInfo(), + mTimeFrameGPU->getDeviceArrayUnsortedClusters(), + mTimeFrameGPU->getDeviceTrackSeedsLUT(), + this->mTrkParams[iteration].LayerRadii, + this->mTrkParams[iteration].MinPt, + this->mTrkParams[iteration].LayerxX0, + trackSeeds.size(), + this->mBz, + startLevel, + this->mTrkParams[iteration].MaxChi2ClusterAttachment, + this->mTrkParams[iteration].MaxChi2NDF, + this->mTrkParams[iteration].ReseedIfShorter, + this->mTrkParams[iteration].RepeatRefitOut, + this->mTrkParams[iteration].ShiftRefToCluster, + mTimeFrameGPU->getDevicePropagator(), + this->mTrkParams[iteration].CorrType, + mTimeFrameGPU->getFrameworkAllocator()); + mTimeFrameGPU->createTrackITSExtDevice(trackSeeds.size()); + computeTrackSeedHandler(mTimeFrameGPU->getDeviceTrackSeeds(), + mTimeFrameGPU->getDeviceArrayTrackingFrameInfo(), + mTimeFrameGPU->getDeviceArrayUnsortedClusters(), + mTimeFrameGPU->getDeviceTrackITSExt(), + mTimeFrameGPU->getDeviceTrackSeedsLUT(), + this->mTrkParams[iteration].LayerRadii, + this->mTrkParams[iteration].MinPt, + this->mTrkParams[iteration].LayerxX0, + trackSeeds.size(), + mTimeFrameGPU->getNTrackSeeds(), + this->mBz, + startLevel, + this->mTrkParams[iteration].MaxChi2ClusterAttachment, + this->mTrkParams[iteration].MaxChi2NDF, + this->mTrkParams[iteration].ReseedIfShorter, + this->mTrkParams[iteration].RepeatRefitOut, + this->mTrkParams[iteration].ShiftRefToCluster, + mTimeFrameGPU->getDevicePropagator(), + this->mTrkParams[iteration].CorrType, + mTimeFrameGPU->getFrameworkAllocator()); + mTimeFrameGPU->downloadTrackITSExtDevice(); auto& tracks = mTimeFrameGPU->getTrackITSExt(); - - for (auto& track : tracks) { - if (!track.getChi2()) { - continue; // this is to skip the unset tracks that are put at the beginning of the vector by the sorting. To see if this can be optimised. - } - int nShared = 0; - bool isFirstShared{false}; - for (int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) { - if (track.getClusterIndex(iLayer) == UnusedIndex) { - continue; - } - nShared += int(mTimeFrameGPU->isClusterUsed(iLayer, track.getClusterIndex(iLayer))); - isFirstShared |= !iLayer && mTimeFrameGPU->isClusterUsed(iLayer, track.getClusterIndex(iLayer)); - } - - if (nShared > mTrkParams[0].ClusterSharing) { - continue; - } - - std::array rofs{INT_MAX, INT_MAX, INT_MAX}; - for (int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) { - if (track.getClusterIndex(iLayer) == UnusedIndex) { - continue; - } - mTimeFrameGPU->markUsedCluster(iLayer, track.getClusterIndex(iLayer)); - int currentROF = mTimeFrameGPU->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; - } - } - } - if (rofs[2] != INT_MAX) { - continue; - } - if (rofs[1] != INT_MAX) { - track.setNextROFbit(); - } - mTimeFrameGPU->getTracks(std::min(rofs[0], rofs[1])).emplace_back(track); - } + this->acceptTracks(iteration, tracks, firstClusters); mTimeFrameGPU->loadUsedClustersDevice(); } - if (iteration == mTrkParams.size() - 1) { - mTimeFrameGPU->unregisterHostMemory(0); - } + this->markTracks(iteration); + // wipe the artefact memory + mTimeFrameGPU->popMemoryStack(iteration); }; -template -int TrackerTraitsGPU::getTFNumberOfClusters() const +template +int TrackerTraitsGPU::getTFNumberOfClusters() const { return mTimeFrameGPU->getNumberOfClusters(); } -template -int TrackerTraitsGPU::getTFNumberOfTracklets() const +template +int TrackerTraitsGPU::getTFNumberOfTracklets() const { return std::accumulate(mTimeFrameGPU->getNTracklets().begin(), mTimeFrameGPU->getNTracklets().end(), 0); } -template -int TrackerTraitsGPU::getTFNumberOfCells() const +template +int TrackerTraitsGPU::getTFNumberOfCells() const { return mTimeFrameGPU->getNumberOfCells(); } -template -void TrackerTraitsGPU::setBz(float bz) +template +void TrackerTraitsGPU::setBz(float bz) { - mBz = bz; + this->mBz = bz; mTimeFrameGPU->setBz(bz); } template class TrackerTraitsGPU<7>; +#ifdef ENABLE_UPGRADES +template class TrackerTraitsGPU<11>; +#endif } // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu index bb39e9e70341b..571afe08fc209 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -23,28 +22,20 @@ #include #include #include -#include #include "ITStracking/Constants.h" +#include "ITStracking/Definitions.h" #include "ITStracking/IndexTableUtils.h" #include "ITStracking/MathUtils.h" +#include "ITStracking/ExternalAllocator.h" +#include "ITStracking/Tracklet.h" +#include "ITStracking/Cluster.h" +#include "ITStracking/Cell.h" +#include "ITStracking/TrackHelpers.h" #include "DataFormatsITS/TrackITS.h" -#include "ReconstructionDataFormats/Vertex.h" - -#include "ITStrackingGPU/TrackerTraitsGPU.h" #include "ITStrackingGPU/TrackingKernels.h" #include "ITStrackingGPU/Utils.h" - -#include "GPUCommonHelpers.h" - -#ifndef __HIPCC__ -#define THRUST_NAMESPACE thrust::cuda -#else -#define THRUST_NAMESPACE thrust::hip -#endif - -#define GPU_BLOCKS GPUCA_DETERMINISTIC_CODE(1, 99999) -#define GPU_THREADS GPUCA_DETERMINISTIC_CODE(1, 99999) +#include "utils/strtag.h" // O2 track model #include "ReconstructionDataFormats/Track.h" @@ -53,134 +44,9 @@ using namespace o2::track; namespace o2::its { -using namespace constants::its2; -using Vertex = o2::dataformats::Vertex>; - -GPUdii() float Sq(float v) -{ - return v * v; -} - namespace gpu { -GPUd() const int4 getBinsRect(const Cluster& currentCluster, const int layerIndex, - const o2::its::IndexTableUtils& utils, - const float z1, const float z2, float maxdeltaz, float maxdeltaphi) -{ - const float zRangeMin = o2::gpu::CAMath::Min(z1, z2) - maxdeltaz; - const float phiRangeMin = (maxdeltaphi > constants::math::Pi) ? 0.f : currentCluster.phi - maxdeltaphi; - const float zRangeMax = o2::gpu::CAMath::Max(z1, z2) + maxdeltaz; - const float phiRangeMax = (maxdeltaphi > constants::math::Pi) ? constants::math::TwoPi : currentCluster.phi + maxdeltaphi; - - if (zRangeMax < -utils.getLayerZ(layerIndex) || - zRangeMin > utils.getLayerZ(layerIndex) || zRangeMin > zRangeMax) { - - return getEmptyBinsRect(); - } - - return int4{o2::gpu::CAMath::Max(0, utils.getZBinIndex(layerIndex, zRangeMin)), - utils.getPhiBinIndex(math_utils::getNormalizedPhi(phiRangeMin)), - o2::gpu::CAMath::Min(utils.getNzBins() - 1, utils.getZBinIndex(layerIndex, zRangeMax)), - utils.getPhiBinIndex(math_utils::getNormalizedPhi(phiRangeMax))}; -} - -GPUd() bool fitTrack(TrackITSExt& track, - int start, - int end, - int step, - float chi2clcut, - float chi2ndfcut, - float maxQoverPt, - int nCl, - float bz, - const TrackingFrameInfo** tfInfos, - const o2::base::Propagator* prop, - o2::base::PropagatorF::MatCorrType matCorrType) -{ - for (int iLayer{start}; iLayer != end; iLayer += step) { - if (track.getClusterIndex(iLayer) == constants::its::UnusedIndex) { - continue; - } - const TrackingFrameInfo& trackingHit = tfInfos[iLayer][track.getClusterIndex(iLayer)]; - if (!track.o2::track::TrackParCovF::rotate(trackingHit.alphaTrackingFrame)) { - return false; - } - - if (!prop->propagateToX(track, - trackingHit.xTrackingFrame, - bz, - o2::base::PropagatorImpl::MAX_SIN_PHI, - o2::base::PropagatorImpl::MAX_STEP, - matCorrType)) { - return false; - } - - if (matCorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) { - const float xx0 = (iLayer > 2) ? 1.e-2f : 5.e-3f; // 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)) { - return false; - } - } - - auto predChi2{track.getPredictedChi2(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)}; - - if ((nCl >= 3 && predChi2 > chi2clcut) || predChi2 < 0.f) { - return false; - } - track.setChi2(track.getChi2() + predChi2); - if (!track.o2::track::TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) { - return false; - } - nCl++; - } - return o2::gpu::CAMath::Abs(track.getQ2Pt()) < maxQoverPt && track.getChi2() < chi2ndfcut * (nCl * 2 - 5); -} - -GPUd() o2::track::TrackParCov buildTrackSeed(const Cluster& cluster1, - const Cluster& cluster2, - const TrackingFrameInfo& tf3, - const float bz) -{ - const float ca = o2::gpu::CAMath::Cos(tf3.alphaTrackingFrame), sa = o2::gpu::CAMath::Sin(tf3.alphaTrackingFrame); - const float x1 = cluster1.xCoordinate * ca + cluster1.yCoordinate * sa; - const float y1 = -cluster1.xCoordinate * sa + cluster1.yCoordinate * ca; - const float z1 = cluster1.zCoordinate; - const float x2 = cluster2.xCoordinate * ca + cluster2.yCoordinate * sa; - const float y2 = -cluster2.xCoordinate * sa + cluster2.yCoordinate * ca; - const float z2 = cluster2.zCoordinate; - const float x3 = tf3.xTrackingFrame; - const float y3 = tf3.positionTrackingFrame[0]; - const float z3 = tf3.positionTrackingFrame[1]; - - const bool zeroField{o2::gpu::CAMath::Abs(bz) < o2::constants::math::Almost0}; - const float tgp = zeroField ? o2::gpu::CAMath::ATan2(y3 - y1, x3 - x1) : 1.f; - const float crv = zeroField ? 1.f : math_utils::computeCurvature(x3, y3, x2, y2, x1, y1); - const float snp = zeroField ? tgp / o2::gpu::CAMath::Sqrt(1.f + tgp * tgp) : crv * (x3 - math_utils::computeCurvatureCentreX(x3, y3, x2, y2, x1, y1)); - 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 q2pt = zeroField ? 1.f / o2::track::kMostProbablePt : crv / (bz * o2::constants::math::B2C); - const float q2pt2 = crv * crv; - const float sg2q2pt = o2::track::kC1Pt2max * (q2pt2 > 0.0005 ? (q2pt2 < 1 ? q2pt2 : 1) : 0.0005); - return track::TrackParCov(tf3.xTrackingFrame, tf3.alphaTrackingFrame, - {y3, z3, snp, 0.5f * (tgl12 + tgl23), q2pt}, - {tf3.covarianceTrackingFrame[0], - tf3.covarianceTrackingFrame[1], tf3.covarianceTrackingFrame[2], - 0.f, 0.f, track::kCSnp2max, - 0.f, 0.f, 0.f, track::kCTgl2max, - 0.f, 0.f, 0.f, 0.f, sg2q2pt}); -} - -struct sort_tracklets { - GPUhd() bool operator()(const Tracklet& a, const Tracklet& b) { return a.firstClusterIndex < b.firstClusterIndex || (a.firstClusterIndex == b.firstClusterIndex && a.secondClusterIndex < b.secondClusterIndex); } -}; - -struct equal_tracklets { - GPUhd() bool operator()(const Tracklet& a, const Tracklet& b) { return a.firstClusterIndex == b.firstClusterIndex && a.secondClusterIndex == b.secondClusterIndex; } -}; - template struct sort_by_second { GPUhd() bool operator()(const gpuPair& a, const gpuPair& b) const { return a.second < b.second; } @@ -218,213 +84,191 @@ struct is_valid_pair { } }; +template struct seed_selector { - float maxQ2Pt; - float maxChi2; - - GPUhd() seed_selector(float maxQ2Pt, float maxChi2) : maxQ2Pt(maxQ2Pt), maxChi2(maxChi2) {} - GPUhd() bool operator()(const CellSeed& seed) const + float mMaxQ2Pt; + float mMaxChi2; + int mMaxHoles; + int mMinTrackLength; + LayerMask mHoleLayerMask; + + GPUhd() seed_selector(float maxQ2Pt, float maxChi2, int maxHoles, int minTrackLength, LayerMask holeLayerMask) : mMaxQ2Pt(maxQ2Pt), mMaxChi2(maxChi2), mMaxHoles(maxHoles), mMinTrackLength(minTrackLength), mHoleLayerMask(holeLayerMask) {} + GPUhd() bool operator()(const TrackSeed& seed) const { - return !(seed.getQ2Pt() > maxQ2Pt || seed.getChi2() > maxChi2); + return !(seed.getQ2Pt() > mMaxQ2Pt || seed.getChi2() > mMaxChi2) && + seed.getHitLayerMask().length() >= mMinTrackLength && + seed.getHitLayerMask().isAllowed(mMaxHoles, mHoleLayerMask); } }; struct compare_track_chi2 { GPUhd() bool operator()(const TrackITSExt& a, const TrackITSExt& b) const { - return a.getChi2() < b.getChi2(); + return o2::its::track::isBetter(a, b); } }; -GPUd() gpuSpan getPrimaryVertices(const int rof, - const int* roframesPV, - const int nROF, - const uint8_t* mask, - const Vertex* vertices) -{ - const int start_pv_id = roframesPV[rof]; - const int stop_rof = rof >= nROF - 1 ? nROF : rof + 1; - size_t delta = mask[rof] ? roframesPV[stop_rof] - start_pv_id : 0; // return empty span if ROF is excluded - return gpuSpan(&vertices[start_pv_id], delta); -}; - -GPUd() gpuSpan getClustersOnLayer(const int rof, - const int totROFs, - const int layer, - const int** roframesClus, - const Cluster** clusters) -{ - if (rof < 0 || rof >= totROFs) { - return gpuSpan(); - } - const int start_clus_id{roframesClus[layer][rof]}; - const int stop_rof = rof >= totROFs - 1 ? totROFs : rof + 1; - const unsigned int delta = roframesClus[layer][stop_rof] - start_clus_id; - return gpuSpan(&(clusters[layer][start_clus_id]), delta); -} - -template -GPUg() void fitTrackSeedsKernel( - CellSeed* trackSeeds, +template +GPUg() void __launch_bounds__(256, 1) fitTrackSeedsKernel( + TrackSeed* trackSeeds, const TrackingFrameInfo** foundTrackingFrameInfo, + const Cluster** unsortedClusters, o2::its::TrackITSExt* tracks, + maybe_const* seedLUT, + const float* layerRadii, const float* minPts, + const float* layerxX0, const unsigned int nSeeds, const float bz, const int startLevel, - float maxChi2ClusterAttachment, - float maxChi2NDF, + const float maxChi2ClusterAttachment, + const float maxChi2NDF, + const int reseedIfShorter, + const bool repeatRefitOut, + const bool shiftRefToCluster, const o2::base::Propagator* propagator, const o2::base::PropagatorF::MatCorrType matCorrType) { for (int iCurrentTrackSeedIndex = blockIdx.x * blockDim.x + threadIdx.x; iCurrentTrackSeedIndex < nSeeds; iCurrentTrackSeedIndex += blockDim.x * gridDim.x) { - auto& seed = trackSeeds[iCurrentTrackSeedIndex]; - TrackITSExt temporaryTrack{seed}; - - temporaryTrack.resetCovariance(); - temporaryTrack.setChi2(0); - int* clusters = seed.getClusters(); - for (int iL{0}; iL < 7; ++iL) { - temporaryTrack.setExternalClusterIndex(iL, clusters[iL], clusters[iL] != constants::its::UnusedIndex); - } - bool fitSuccess = fitTrack(temporaryTrack, // TrackITSExt& track, - 0, // int lastLayer, - nLayers, // int firstLayer, - 1, // int firstCluster, - maxChi2ClusterAttachment, // float maxChi2ClusterAttachment, - maxChi2NDF, // float maxChi2NDF, - o2::constants::math::VeryBig, // float maxQoverPt, - 0, // nCl, - bz, // float bz, - foundTrackingFrameInfo, // TrackingFrameInfo** trackingFrameInfo, - propagator, // const o2::base::Propagator* propagator, - matCorrType); // o2::base::PropagatorF::MatCorrType matCorrType - if (!fitSuccess) { - continue; + if constexpr (!initRun) { + if (seedLUT[iCurrentTrackSeedIndex] == seedLUT[iCurrentTrackSeedIndex + 1]) { + continue; + } } - temporaryTrack.getParamOut() = temporaryTrack.getParamIn(); - temporaryTrack.resetCovariance(); - temporaryTrack.setChi2(0); - - fitSuccess = fitTrack(temporaryTrack, // TrackITSExt& track, - nLayers - 1, // int lastLayer, - -1, // int firstLayer, - -1, // int firstCluster, - maxChi2ClusterAttachment, // float maxChi2ClusterAttachment, - maxChi2NDF, // float maxChi2NDF, - 50.f, // float maxQoverPt, - 0, // nCl, - bz, // float bz, - foundTrackingFrameInfo, // TrackingFrameInfo** trackingFrameInfo, - propagator, // const o2::base::Propagator* propagator, - matCorrType); // o2::base::PropagatorF::MatCorrType matCorrType - if (!fitSuccess || temporaryTrack.getPt() < minPts[nLayers - temporaryTrack.getNClusters()]) { - continue; + TrackITSExt temporaryTrack; + bool refitSuccess = o2::its::track::refitTrack(trackSeeds[iCurrentTrackSeedIndex], + temporaryTrack, + maxChi2ClusterAttachment, + maxChi2NDF, + bz, + foundTrackingFrameInfo, + unsortedClusters, + layerxX0, + layerRadii, + minPts, + propagator, + matCorrType, + reseedIfShorter, + shiftRefToCluster, + repeatRefitOut); + if (refitSuccess) { + if constexpr (initRun) { + seedLUT[iCurrentTrackSeedIndex] = 1; + } else { + tracks[seedLUT[iCurrentTrackSeedIndex]] = temporaryTrack; + } } - tracks[iCurrentTrackSeedIndex] = temporaryTrack; } } -template // Version for new tracker to supersede the old one -GPUg() void computeLayerCellNeighboursKernel( +template +GPUg() void __launch_bounds__(256, 1) computeLayerCellNeighboursKernel( CellSeed** cellSeedArray, - int* neighboursLUT, - int* neighboursIndexTable, + int* neighboursCursor, int** cellsLUTs, - gpuPair* cellNeighbours, + CellNeighbour* cellNeighbours, + const int sourceCellTopologyId, + const int targetCellTopologyId, const float maxChi2ClusterAttachment, const float bz, - const int layerIndex, - const unsigned int nCells, - const int maxCellNeighbours = 1e2) + const unsigned int nCells) { for (int iCurrentCellIndex = blockIdx.x * blockDim.x + threadIdx.x; iCurrentCellIndex < nCells; iCurrentCellIndex += blockDim.x * gridDim.x) { - const auto& currentCellSeed{cellSeedArray[layerIndex][iCurrentCellIndex]}; + const auto& currentCellSeed{cellSeedArray[sourceCellTopologyId][iCurrentCellIndex]}; const int nextLayerTrackletIndex{currentCellSeed.getSecondTrackletIndex()}; - const int nextLayerFirstCellIndex{cellsLUTs[layerIndex + 1][nextLayerTrackletIndex]}; - const int nextLayerLastCellIndex{cellsLUTs[layerIndex + 1][nextLayerTrackletIndex + 1]}; - int foundNeighbours{0}; + const int nextLayerFirstCellIndex{cellsLUTs[targetCellTopologyId][nextLayerTrackletIndex]}; + const int nextLayerLastCellIndex{cellsLUTs[targetCellTopologyId][nextLayerTrackletIndex + 1]}; for (int iNextCell{nextLayerFirstCellIndex}; iNextCell < nextLayerLastCellIndex; ++iNextCell) { - CellSeed nextCellSeed{cellSeedArray[layerIndex + 1][iNextCell]}; // Copy - if (nextCellSeed.getFirstTrackletIndex() != nextLayerTrackletIndex) { // Check if cells share the same tracklet + auto nextCellSeed{cellSeedArray[targetCellTopologyId][iNextCell]}; // Copy + if (nextCellSeed.getFirstTrackletIndex() != nextLayerTrackletIndex || !currentCellSeed.getTimeStamp().isCompatible(nextCellSeed.getTimeStamp())) { break; } + if (!nextCellSeed.rotate(currentCellSeed.getAlpha()) || !nextCellSeed.propagateTo(currentCellSeed.getX(), bz)) { continue; } + float chi2 = currentCellSeed.getPredictedChi2(nextCellSeed); - if (chi2 > maxChi2ClusterAttachment) /// TODO: switch to the chi2 wrt cluster to avoid correlation - { + if (chi2 > maxChi2ClusterAttachment) { continue; } + if constexpr (initRun) { - atomicAdd(neighboursLUT + iNextCell, 1); - foundNeighbours++; - neighboursIndexTable[iCurrentCellIndex]++; + atomicAdd(neighboursCursor + iNextCell, 1); } else { - cellNeighbours[neighboursIndexTable[iCurrentCellIndex] + foundNeighbours] = {iCurrentCellIndex, iNextCell}; - foundNeighbours++; - // FIXME: this is prone to race conditions: check on level is not atomic + const int offset = atomicAdd(neighboursCursor + iNextCell, 1); + cellNeighbours[offset] = {sourceCellTopologyId, iCurrentCellIndex, targetCellTopologyId, iNextCell, currentCellSeed.getLevel() + 1}; const int currentCellLevel{currentCellSeed.getLevel()}; if (currentCellLevel >= nextCellSeed.getLevel()) { - cellSeedArray[layerIndex + 1][iNextCell].setLevel(currentCellLevel + 1); + atomicMax(cellSeedArray[targetCellTopologyId][iNextCell].getLevelPtr(), currentCellLevel + 1); } } } } } -template -GPUg() void computeLayerCellsKernel( +template +GPUg() void __launch_bounds__(256, 1) computeLayerCellsKernel( const Cluster** sortedClusters, const Cluster** unsortedClusters, const TrackingFrameInfo** tfInfo, Tracklet** tracklets, int** trackletsLUT, const int nTrackletsCurrent, - const int layer, + const int cellTopologyId, + const typename TrackingTopology::View topology, CellSeed* cells, int** cellsLUTs, + const float* layerxX0, const float bz, const float maxChi2ClusterAttachment, const float cellDeltaTanLambdaSigma, const float nSigmaCut) { - constexpr float radl = 9.36f; // Radiation length of Si [cm]. - constexpr float rho = 2.33f; // Density of Si [g/cm^3]. - constexpr float layerxX0[7] = {5.e-3f, 5.e-3f, 5.e-3f, 1.e-2f, 1.e-2f, 1.e-2f, 1.e-2f}; // Hardcoded here for the moment. + const auto cellTopology = topology.getCell(cellTopologyId); + const auto first = topology.getTransition(cellTopology.firstTransition); + const auto second = topology.getTransition(cellTopology.secondTransition); + const int layers[3] = {first.fromLayer, first.toLayer, second.toLayer}; for (int iCurrentTrackletIndex = blockIdx.x * blockDim.x + threadIdx.x; iCurrentTrackletIndex < nTrackletsCurrent; iCurrentTrackletIndex += blockDim.x * gridDim.x) { - const Tracklet& currentTracklet = tracklets[layer][iCurrentTrackletIndex]; + if constexpr (!initRun) { + if (cellsLUTs[cellTopologyId][iCurrentTrackletIndex] == cellsLUTs[cellTopologyId][iCurrentTrackletIndex + 1]) { + continue; + } + } + const Tracklet& currentTracklet = tracklets[cellTopology.firstTransition][iCurrentTrackletIndex]; const int nextLayerClusterIndex{currentTracklet.secondClusterIndex}; - const int nextLayerFirstTrackletIndex{trackletsLUT[layer + 1][nextLayerClusterIndex]}; - const int nextLayerLastTrackletIndex{trackletsLUT[layer + 1][nextLayerClusterIndex + 1]}; + const int nextLayerFirstTrackletIndex{trackletsLUT[cellTopology.secondTransition][nextLayerClusterIndex]}; + const int nextLayerLastTrackletIndex{trackletsLUT[cellTopology.secondTransition][nextLayerClusterIndex + 1]}; if (nextLayerFirstTrackletIndex == nextLayerLastTrackletIndex) { continue; } int foundCells{0}; for (int iNextTrackletIndex{nextLayerFirstTrackletIndex}; iNextTrackletIndex < nextLayerLastTrackletIndex; ++iNextTrackletIndex) { - if (tracklets[layer + 1][iNextTrackletIndex].firstClusterIndex != nextLayerClusterIndex) { + if (tracklets[cellTopology.secondTransition][iNextTrackletIndex].firstClusterIndex != nextLayerClusterIndex) { break; } - const Tracklet& nextTracklet = tracklets[layer + 1][iNextTrackletIndex]; + const Tracklet& nextTracklet = tracklets[cellTopology.secondTransition][iNextTrackletIndex]; + if (!currentTracklet.getTimeStamp().isCompatible(nextTracklet.getTimeStamp())) { + continue; + } const float deltaTanLambda{o2::gpu::CAMath::Abs(currentTracklet.tanLambda - nextTracklet.tanLambda)}; if (deltaTanLambda / cellDeltaTanLambdaSigma < nSigmaCut) { const int clusId[3]{ - sortedClusters[layer][currentTracklet.firstClusterIndex].clusterId, - sortedClusters[layer + 1][nextTracklet.firstClusterIndex].clusterId, - sortedClusters[layer + 2][nextTracklet.secondClusterIndex].clusterId}; - - const auto& cluster1_glo = unsortedClusters[layer][clusId[0]]; - const auto& cluster2_glo = unsortedClusters[layer + 1][clusId[1]]; - const auto& cluster3_tf = tfInfo[layer + 2][clusId[2]]; - auto track{buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_tf, bz)}; + sortedClusters[layers[0]][currentTracklet.firstClusterIndex].clusterId, + sortedClusters[layers[1]][nextTracklet.firstClusterIndex].clusterId, + sortedClusters[layers[2]][nextTracklet.secondClusterIndex].clusterId}; + + const auto& cluster1_glo = unsortedClusters[layers[0]][clusId[0]]; + const auto& cluster2_glo = unsortedClusters[layers[1]][clusId[1]]; + const auto& cluster3_tf = tfInfo[layers[2]][clusId[2]]; + auto track{o2::its::track::buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_tf, bz)}; float chi2{0.f}; bool good{false}; for (int iC{2}; iC--;) { - const TrackingFrameInfo& trackingHit = tfInfo[layer + iC][clusId[iC]]; + const TrackingFrameInfo& trackingHit = tfInfo[layers[iC]][clusId[iC]]; if (!track.rotate(trackingHit.alphaTrackingFrame)) { break; } @@ -432,7 +276,7 @@ GPUg() void computeLayerCellsKernel( break; } - if (!track.correctForMaterial(layerxX0[layer + iC], layerxX0[layer] * radl * rho, true)) { + if (!track.correctForMaterial(layerxX0[layers[iC]], layerxX0[layers[iC]] * constants::Radl * constants::Rho, true)) { break; } @@ -450,82 +294,112 @@ GPUg() void computeLayerCellsKernel( continue; } if constexpr (!initRun) { - new (cells + cellsLUTs[layer][iCurrentTrackletIndex] + foundCells) CellSeed{layer, clusId[0], clusId[1], clusId[2], iCurrentTrackletIndex, iNextTrackletIndex, track, chi2}; + TimeEstBC ts = currentTracklet.getTimeStamp(); + ts += nextTracklet.getTimeStamp(); + new (cells + cellsLUTs[cellTopologyId][iCurrentTrackletIndex] + foundCells) CellSeed{cellTopology.hitLayerMask, clusId[0], clusId[1], clusId[2], iCurrentTrackletIndex, iNextTrackletIndex, track, chi2, ts}; } ++foundCells; - if constexpr (initRun) { - cellsLUTs[layer][iCurrentTrackletIndex] = foundCells; - } } } + if constexpr (initRun) { + cellsLUTs[cellTopologyId][iCurrentTrackletIndex] = foundCells; + } } } -template -GPUg() void computeLayerTrackletsMultiROFKernel( - const IndexTableUtils* utils, - const uint8_t* multMask, - const int layerIndex, - const int startROF, - const int endROF, - const int totalROFs, - const int deltaROF, +template +GPUg() void __launch_bounds__(256, 1) computeLayerTrackletsMultiROFKernel( + const IndexTableUtils* utils, + const typename ROFMaskTable::View rofMask, + const int transitionId, + const typename TrackingTopology::View topology, + const typename ROFOverlapTable::View rofOverlaps, + const typename ROFVertexLookupTable::View vertexLUT, const Vertex* vertices, const int* rofPV, - const int nVertices, const int vertexId, - const Cluster** clusters, // Input data rof0 - const int** ROFClusters, // Number of clusters on layers per ROF - const unsigned char** usedClusters, // Used clusters - const int** indexTables, // Input data rof0-delta getNphiBins()}; const int zBins{utils->getNzBins()}; - for (unsigned int iROF{blockIdx.x}; iROF < endROF - startROF; iROF += gridDim.x) { - const short rof0 = iROF + startROF; - auto primaryVertices = getPrimaryVertices(rof0, rofPV, totalROFs, multMask, vertices); + const int tableSize{phiBins * zBins + 1}; + const int totalROFs0 = rofOverlaps.getLayer(fromLayer).mNROFsTF; + const int totalROFs1 = rofOverlaps.getLayer(toLayer).mNROFsTF; + for (unsigned int pivotROF{blockIdx.x}; pivotROF < totalROFs0; pivotROF += gridDim.x) { + if (!rofMask.isROFEnabled(fromLayer, pivotROF)) { + continue; + } + + const auto& pvs = vertexLUT.getVertices(fromLayer, pivotROF); + auto primaryVertices = gpuSpan(&vertices[pvs.getFirstEntry()], pvs.getEntries()); + if (primaryVertices.empty()) { + continue; + } const auto startVtx{vertexId >= 0 ? vertexId : 0}; const auto endVtx{vertexId >= 0 ? o2::gpu::CAMath::Min(vertexId + 1, static_cast(primaryVertices.size())) : static_cast(primaryVertices.size())}; - const short minROF = o2::gpu::CAMath::Max(startROF, static_cast(rof0 - deltaROF)); - const short maxROF = o2::gpu::CAMath::Min(endROF - 1, static_cast(rof0 + deltaROF)); - auto clustersCurrentLayer = getClustersOnLayer(rof0, totalROFs, layerIndex, ROFClusters, clusters); + if (endVtx <= startVtx || (vertexId + 1) > primaryVertices.size()) { + continue; + } + + const auto& rofOverlap = rofOverlaps.getOverlap(fromLayer, toLayer, pivotROF); + if (!rofOverlap.getEntries()) { + continue; + } + + auto clustersCurrentLayer = getClustersOnLayer(pivotROF, totalROFs0, fromLayer, ROFClusters, clusters); if (clustersCurrentLayer.empty()) { continue; } for (int currentClusterIndex = threadIdx.x; currentClusterIndex < clustersCurrentLayer.size(); currentClusterIndex += blockDim.x) { + unsigned int storedTracklets{0}; - auto currentCluster{clustersCurrentLayer[currentClusterIndex]}; - const int currentSortedIndex{ROFClusters[layerIndex][rof0] + currentClusterIndex}; - if (usedClusters[layerIndex][currentCluster.clusterId]) { + const auto& currentCluster{clustersCurrentLayer[currentClusterIndex]}; + const int currentSortedIndex{ROFClusters[fromLayer][pivotROF] + currentClusterIndex}; + if (usedClusters[fromLayer][currentCluster.clusterId]) { continue; } + if constexpr (!initRun) { + if (trackletsLUT[transitionId][currentSortedIndex] == trackletsLUT[transitionId][currentSortedIndex + 1]) { + continue; + } + } const float inverseR0{1.f / currentCluster.radius}; for (int iV{startVtx}; iV < endVtx; ++iV) { auto& primaryVertex{primaryVertices[iV]}; - if (primaryVertex.isFlagSet(2) && iteration != 3) { + if (!vertexLUT.isVertexCompatible(fromLayer, pivotROF, primaryVertex)) { + continue; + } + if (primaryVertex.isFlagSet(Vertex::Flags::UPCMode) != selectUPCVertices) { continue; } - const float resolution = o2::gpu::CAMath::Sqrt(Sq(resolutionPV) / primaryVertex.getNContributors() + Sq(positionResolution)); + + const float resolution = o2::gpu::CAMath::Sqrt(math_utils::Sq(resolutionPV) / primaryVertex.getNContributors() + math_utils::Sq(positionResolution)); const float tanLambda{(currentCluster.zCoordinate - primaryVertex.getZ()) * inverseR0}; const float zAtRmin{tanLambda * (minR - currentCluster.radius) + currentCluster.zCoordinate}; const float zAtRmax{tanLambda * (maxR - currentCluster.radius) + currentCluster.zCoordinate}; - const float sqInverseDeltaZ0{1.f / (Sq(currentCluster.zCoordinate - primaryVertex.getZ()) + 2.e-8f)}; /// protecting from overflows adding the detector resolution - const float sigmaZ{o2::gpu::CAMath::Sqrt(Sq(resolution) * Sq(tanLambda) * ((Sq(inverseR0) + sqInverseDeltaZ0) * Sq(meanDeltaR) + 1.f) + Sq(meanDeltaR * MSAngle))}; - const int4 selectedBinsRect{getBinsRect(currentCluster, layerIndex + 1, *utils, zAtRmin, zAtRmax, sigmaZ * NSigmaCut, phiCut)}; - if (selectedBinsRect.x == 0 && selectedBinsRect.y == 0 && selectedBinsRect.z == 0 && selectedBinsRect.w == 0) { + const float sqInverseDeltaZ0{1.f / (math_utils::Sq(currentCluster.zCoordinate - primaryVertex.getZ()) + constants::Tolerance)}; /// protecting from overflows adding the detector resolution + const float sigmaZ{o2::gpu::CAMath::Sqrt(math_utils::Sq(resolution) * math_utils::Sq(tanLambda) * ((math_utils::Sq(inverseR0) + sqInverseDeltaZ0) * math_utils::Sq(meanDeltaR) + 1.f) + math_utils::Sq(meanDeltaR * MSAngle))}; + const int4 selectedBinsRect{o2::its::getBinsRect(currentCluster, toLayer, zAtRmin, zAtRmax, sigmaZ * NSigmaCut, phiCut, *utils)}; + if (selectedBinsRect.x < 0) { continue; } int phiBinsNum{selectedBinsRect.w - selectedBinsRect.y + 1}; @@ -534,36 +408,42 @@ GPUg() void computeLayerTrackletsMultiROFKernel( phiBinsNum += phiBins; } - const int tableSize{phiBins * zBins + 1}; - for (short rof1{minROF}; rof1 <= maxROF; ++rof1) { - auto clustersNextLayer = getClustersOnLayer(rof1, totalROFs, layerIndex + 1, ROFClusters, clusters); + for (short targetROF = rofOverlap.getFirstEntry(); targetROF < rofOverlap.getEntriesBound(); ++targetROF) { + if (!rofMask.isROFEnabled(toLayer, targetROF)) { + continue; + } + auto clustersNextLayer = getClustersOnLayer(targetROF, totalROFs1, toLayer, ROFClusters, clusters); if (clustersNextLayer.empty()) { continue; } + const auto ts = rofOverlaps.getTimeStamp(fromLayer, pivotROF, toLayer, targetROF); + if (!ts.isCompatible(primaryVertex.getTimeStamp())) { + continue; + } for (int iPhiCount{0}; iPhiCount < phiBinsNum; iPhiCount++) { int iPhiBin = (selectedBinsRect.y + iPhiCount) % phiBins; const int firstBinIndex{utils->getBinIndex(selectedBinsRect.x, iPhiBin)}; const int maxBinIndex{firstBinIndex + selectedBinsRect.z - selectedBinsRect.x + 1}; - const int firstRowClusterIndex = indexTables[layerIndex + 1][(rof1 - startROF) * tableSize + firstBinIndex]; - const int maxRowClusterIndex = indexTables[layerIndex + 1][(rof1 - startROF) * tableSize + maxBinIndex]; + const int firstRowClusterIndex = indexTables[toLayer][(targetROF)*tableSize + firstBinIndex]; + const int maxRowClusterIndex = indexTables[toLayer][(targetROF)*tableSize + maxBinIndex]; for (int nextClusterIndex{firstRowClusterIndex}; nextClusterIndex < maxRowClusterIndex; ++nextClusterIndex) { if (nextClusterIndex >= clustersNextLayer.size()) { break; } const Cluster& nextCluster{clustersNextLayer[nextClusterIndex]}; - if (usedClusters[layerIndex + 1][nextCluster.clusterId]) { + if (usedClusters[toLayer][nextCluster.clusterId]) { continue; } const float deltaPhi{o2::gpu::CAMath::Abs(currentCluster.phi - nextCluster.phi)}; const float deltaZ{o2::gpu::CAMath::Abs(tanLambda * (nextCluster.radius - currentCluster.radius) + currentCluster.zCoordinate - nextCluster.zCoordinate)}; - const int nextSortedIndex{ROFClusters[layerIndex + 1][rof1] + nextClusterIndex}; - if (deltaZ / sigmaZ < NSigmaCut && (deltaPhi < phiCut || o2::gpu::CAMath::Abs(deltaPhi - constants::math::TwoPi) < phiCut)) { + if (deltaZ / sigmaZ < NSigmaCut && (deltaPhi < phiCut || o2::gpu::CAMath::Abs(deltaPhi - o2::constants::math::TwoPI) < phiCut)) { if constexpr (initRun) { - trackletsLUT[layerIndex][currentSortedIndex]++; // we need l0 as well for usual exclusive sums. + trackletsLUT[transitionId][currentSortedIndex]++; // we need l0 as well for usual exclusive sums. } else { const float phi{o2::gpu::CAMath::ATan2(currentCluster.yCoordinate - nextCluster.yCoordinate, currentCluster.xCoordinate - nextCluster.xCoordinate)}; const float tanL{(currentCluster.zCoordinate - nextCluster.zCoordinate) / (currentCluster.radius - nextCluster.radius)}; - new (tracklets[layerIndex] + trackletsLUT[layerIndex][currentSortedIndex] + storedTracklets) Tracklet{currentSortedIndex, nextSortedIndex, tanL, phi, rof0, rof1}; + const int nextSortedIndex{ROFClusters[toLayer][targetROF] + nextClusterIndex}; + new (tracklets[transitionId] + trackletsLUT[transitionId][currentSortedIndex] + storedTracklets) Tracklet{currentSortedIndex, nextSortedIndex, tanL, phi, ts}; } ++storedTracklets; } @@ -575,69 +455,91 @@ GPUg() void computeLayerTrackletsMultiROFKernel( } } -template -GPUg() void compileTrackletsLookupTableKernel(const Tracklet* tracklets, - int* trackletsLookUpTable, - const int nTracklets) +GPUg() void __launch_bounds__(256, 1) compileTrackletsLookupTableKernel( + const Tracklet* tracklets, + int* trackletsLookUpTable, + const int nTracklets) { for (int currentTrackletIndex = blockIdx.x * blockDim.x + threadIdx.x; currentTrackletIndex < nTracklets; currentTrackletIndex += blockDim.x * gridDim.x) { atomicAdd(&trackletsLookUpTable[tracklets[currentTrackletIndex].firstClusterIndex], 1); } } -template -GPUg() void processNeighboursKernel(const int layer, - const int level, - CellSeed** allCellSeeds, - CellSeed* currentCellSeeds, - const int* currentCellIds, - const unsigned int nCurrentCells, - CellSeed* updatedCellSeeds, - int* updatedCellsIds, - int* foundSeedsTable, // auxiliary only in GPU code to compute the number of cells per iteration - const unsigned char** usedClusters, // Used clusters - int* neighbours, - int* neighboursLUT, - const TrackingFrameInfo** foundTrackingFrameInfo, - const float bz, - const float maxChi2ClusterAttachment, - const o2::base::Propagator* propagator, - const o2::base::PropagatorF::MatCorrType matCorrType) +template +GPUg() void __launch_bounds__(256, 1) processNeighboursKernel( + const int defaultCellTopologyId, + const int level, + CellSeed** allCellSeeds, + CurrentSeed* currentCellSeeds, + const int* currentCellIds, + const int* currentCellTopologyIds, + const unsigned int nCurrentCells, + TrackSeed* updatedCellSeeds, + int* updatedCellsIds, + int* updatedCellTopologyIds, + int* foundSeedsTable, // auxiliary only in GPU code to compute the number of cells per iteration + const unsigned char** usedClusters, // Used clusters + CellNeighbour** neighbours, + int** neighboursLUT, + const TrackingFrameInfo** foundTrackingFrameInfo, + const float* layerxX0, + const float bz, + const float maxChi2ClusterAttachment, + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType) { - constexpr float radl = 9.36f; // Radiation length of Si [cm]. - constexpr float rho = 2.33f; // Density of Si [g/cm^3]. - constexpr float layerxX0[7] = {5.e-3f, 5.e-3f, 5.e-3f, 1.e-2f, 1.e-2f, 1.e-2f, 1.e-2f}; // Hardcoded here for the moment. for (unsigned int iCurrentCell = blockIdx.x * blockDim.x + threadIdx.x; iCurrentCell < nCurrentCells; iCurrentCell += blockDim.x * gridDim.x) { + if constexpr (!dryRun) { + if (foundSeedsTable[iCurrentCell] == foundSeedsTable[iCurrentCell + 1]) { + continue; + } + } int foundSeeds{0}; const auto& currentCell{currentCellSeeds[iCurrentCell]}; + const int cellTopologyId = currentCellTopologyIds == nullptr ? defaultCellTopologyId : currentCellTopologyIds[iCurrentCell]; if (currentCell.getLevel() != level) { continue; } - if (currentCellIds == nullptr && (usedClusters[layer][currentCell.getFirstClusterIndex()] || - usedClusters[layer + 1][currentCell.getSecondClusterIndex()] || - usedClusters[layer + 2][currentCell.getThirdClusterIndex()])) { - continue; + if (currentCellIds == nullptr) { + bool used = false; + for (int layer = 0; layer < NLayers; ++layer) { + const int clusterIndex = currentCell.getCluster(layer); + used |= clusterIndex != constants::UnusedIndex && usedClusters[layer][clusterIndex]; + } + if (used) { + continue; + } } const int cellId = currentCellIds == nullptr ? iCurrentCell : currentCellIds[iCurrentCell]; + if (cellTopologyId < 0 || neighboursLUT[cellTopologyId] == nullptr || neighbours[cellTopologyId] == nullptr) { + continue; + } - const int startNeighbourId{cellId ? neighboursLUT[cellId - 1] : 0}; - const int endNeighbourId{neighboursLUT[cellId]}; + const int startNeighbourId{neighboursLUT[cellTopologyId][cellId]}; + const int endNeighbourId{neighboursLUT[cellTopologyId][cellId + 1]}; for (int iNeighbourCell{startNeighbourId}; iNeighbourCell < endNeighbourId; ++iNeighbourCell) { - const int neighbourCellId = neighbours[iNeighbourCell]; - const CellSeed& neighbourCell = allCellSeeds[layer - 1][neighbourCellId]; + const auto& neighbourRef = neighbours[cellTopologyId][iNeighbourCell]; + const int neighbourCellTopologyId = neighbourRef.cellTopology; + const int neighbourCellId = neighbourRef.cell; + const auto& neighbourCell = allCellSeeds[neighbourCellTopologyId][neighbourCellId]; if (neighbourCell.getSecondTrackletIndex() != currentCell.getFirstTrackletIndex()) { continue; } - if (usedClusters[layer - 1][neighbourCell.getFirstClusterIndex()]) { + if (!currentCell.getTimeStamp().isCompatible(neighbourCell.getTimeStamp())) { continue; } if (currentCell.getLevel() - 1 != neighbourCell.getLevel()) { continue; } - CellSeed seed{currentCell}; - auto& trHit = foundTrackingFrameInfo[layer - 1][neighbourCell.getFirstClusterIndex()]; + const int neighbourLayer = neighbourCell.getInnerLayer(); + const int neighbourCluster = neighbourCell.getFirstClusterIndex(); + if (usedClusters[neighbourLayer][neighbourCluster]) { + continue; + } + TrackSeed seed{currentCell}; + auto& trHit = foundTrackingFrameInfo[neighbourLayer][neighbourCluster]; if (!seed.rotate(trHit.alphaTrackingFrame)) { continue; @@ -648,7 +550,7 @@ GPUg() void processNeighboursKernel(const int layer, } if (matCorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) { - if (!seed.correctForMaterial(layerxX0[layer - 1], layerxX0[layer - 1] * radl * rho, true)) { + if (!seed.correctForMaterial(layerxX0[neighbourLayer], layerxX0[neighbourLayer] * constants::Radl * constants::Rho, true)) { continue; } } @@ -661,14 +563,18 @@ GPUg() void processNeighboursKernel(const int layer, if (!seed.o2::track::TrackParCov::update(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)) { continue; } - seed.getClusters()[layer - 1] = neighbourCell.getFirstClusterIndex(); - seed.setLevel(neighbourCell.getLevel()); - seed.setFirstTrackletIndex(neighbourCell.getFirstTrackletIndex()); - seed.setSecondTrackletIndex(neighbourCell.getSecondTrackletIndex()); if constexpr (dryRun) { foundSeedsTable[iCurrentCell]++; } else { + seed.getClusters()[neighbourLayer] = neighbourCluster; + auto mask = seed.getHitLayerMask(); + mask.set(neighbourLayer); + seed.setHitLayerMask(mask); + seed.setLevel(neighbourCell.getLevel()); + seed.setFirstTrackletIndex(neighbourCell.getFirstTrackletIndex()); + seed.setSecondTrackletIndex(neighbourCell.getSecondTrackletIndex()); updatedCellsIds[foundSeedsTable[iCurrentCell] + foundSeeds] = neighbourCellId; + updatedCellTopologyIds[foundSeedsTable[iCurrentCell] + foundSeeds] = neighbourCellTopologyId; updatedCellSeeds[foundSeedsTable[iCurrentCell] + foundSeeds] = seed; } foundSeeds++; @@ -676,183 +582,19 @@ GPUg() void processNeighboursKernel(const int layer, } } -///////////////////////////////////////// -// Debug Kernels -///////////////////////////////////////// - -template -GPUd() void pPointer(T* ptr) -{ - printf("[%p]\t", ptr); -} - -template -GPUg() void printPointersKernel(std::tuple args) -{ - auto print_all = [&](auto... ptrs) { - (pPointer(ptrs), ...); - }; - std::apply(print_all, args); -} - -template -struct trackletSortEmptyFunctor { - GPUhd() bool operator()(const T& lhs, const T& rhs) const - { - return lhs.firstClusterIndex > rhs.firstClusterIndex; - } -}; - -template -struct trackletSortIndexFunctor { - GPUhd() bool operator()(const T& lhs, const T& rhs) const - { - return lhs.firstClusterIndex < rhs.firstClusterIndex || (lhs.firstClusterIndex == rhs.firstClusterIndex && lhs.secondClusterIndex < rhs.secondClusterIndex); - } -}; - -GPUg() void printBufferLayerOnThread(const int layer, const int* v, unsigned int size, const int len = 150, const unsigned int tId = 0) -{ - if (blockIdx.x * blockDim.x + threadIdx.x == tId) { - for (int i{0}; i < size; ++i) { - if (!(i % len)) { - printf("\n layer %d: ===> %d/%d\t", layer, i, (int)size); - } - printf("%d\t", v[i]); - } - printf("\n"); - } -} - -GPUg() void printMatrixRow(const int row, int** mat, const unsigned int rowLength, const int len = 150, const unsigned int tId = 0) -{ - if (blockIdx.x * blockDim.x + threadIdx.x == tId) { - for (int i{0}; i < rowLength; ++i) { - if (!(i % len)) { - printf("\n row %d: ===> %d/%d\t", row, i, (int)rowLength); - } - printf("%d\t", mat[row][i]); - } - printf("\n"); - } -} - -GPUg() void printBufferPointersLayerOnThread(const int layer, void** v, unsigned int size, const int len = 150, const unsigned int tId = 0) -{ - if (blockIdx.x * blockDim.x + threadIdx.x == tId) { - for (int i{0}; i < size; ++i) { - if (!(i % len)) { - printf("\n layer %d: ===> %d/%d\t", layer, i, (int)size); - } - printf("%p\t", (void*)v[i]); - } - printf("\n"); - } -} - -GPUg() void printVertices(const Vertex* v, unsigned int size, const unsigned int tId = 0) -{ - if (blockIdx.x * blockDim.x + threadIdx.x == tId) { - printf("vertices: \n"); - for (int i{0}; i < size; ++i) { - printf("\tx=%f y=%f z=%f\n", v[i].getX(), v[i].getY(), v[i].getZ()); - } - } -} - -GPUg() void printNeighbours(const gpuPair* neighbours, - const int* nNeighboursIndexTable, - const unsigned int nCells, - const unsigned int tId = 0) -{ - for (unsigned int iNeighbour{0}; iNeighbour < nNeighboursIndexTable[nCells]; ++iNeighbour) { - if (threadIdx.x == tId) { - printf("%d -> %d\n", neighbours[iNeighbour].first, neighbours[iNeighbour].second); - } - } -} - -GPUg() void printTrackletsLUTPerROF(const int layerId, - const int** ROFClusters, - int** luts, - const int tId = 0) -{ - if (blockIdx.x * blockDim.x + threadIdx.x == tId) { - for (auto rofId{0}; rofId < 2304; ++rofId) { - int nClus = ROFClusters[layerId][rofId + 1] - ROFClusters[layerId][rofId]; - if (!nClus) { - continue; - } - printf("rof: %d (%d) ==> ", rofId, nClus); - - for (int iC{0}; iC < nClus; ++iC) { - int nT = luts[layerId][ROFClusters[layerId][rofId] + iC]; - printf("%d\t", nT); - } - printf("\n"); - } - } -} - -GPUg() void printCellSeeds(CellSeed* seed, int nCells, const unsigned int tId = 0) -{ - for (unsigned int iCell{0}; iCell < nCells; ++iCell) { - if (threadIdx.x == tId) { - seed[iCell].printCell(); - } - } -} - -template -GPUhi() void cubExclusiveScanInPlace(T* in_out, int num_items, cudaStream_t stream = nullptr) -{ - void* d_temp_storage = nullptr; - size_t temp_storage_bytes = 0; - GPUChkErrS(cub::DeviceScan::ExclusiveSum(d_temp_storage, temp_storage_bytes, in_out, - in_out, num_items, stream)); - GPUChkErrS(cudaMalloc(&d_temp_storage, temp_storage_bytes)); - GPUChkErrS(cub::DeviceScan::ExclusiveSum(d_temp_storage, temp_storage_bytes, in_out, - in_out, num_items, stream)); - GPUChkErrS(cudaFree(d_temp_storage)); -} - -template -GPUhi() void cubExclusiveScanInPlace(Vector& in_out, int num_items, cudaStream_t stream = nullptr) -{ - cubExclusiveScanInPlace(thrust::raw_pointer_cast(in_out.data()), num_items, stream); -} - -template -GPUhi() void cubInclusiveScanInPlace(T* in_out, int num_items, cudaStream_t stream = nullptr) -{ - void* d_temp_storage = nullptr; - size_t temp_storage_bytes = 0; - GPUChkErrS(cub::DeviceScan::InclusiveSum(d_temp_storage, temp_storage_bytes, in_out, - in_out, num_items, stream)); - GPUChkErrS(cudaMalloc(&d_temp_storage, temp_storage_bytes)); - GPUChkErrS(cub::DeviceScan::InclusiveSum(d_temp_storage, temp_storage_bytes, in_out, - in_out, num_items, stream)); - GPUChkErrS(cudaFree(d_temp_storage)); -} - -template -GPUhi() void cubInclusiveScanInPlace(Vector& in_out, int num_items, cudaStream_t stream = nullptr) -{ - cubInclusiveScanInPlace(thrust::raw_pointer_cast(in_out.data()), num_items, stream); -} } // namespace gpu -template -void countTrackletsInROFsHandler(const IndexTableUtils* utils, - const uint8_t* multMask, - const int startROF, - const int endROF, - const int maxROF, - const int deltaROF, +template +void countTrackletsInROFsHandler(const IndexTableUtils* utils, + const typename ROFMaskTable::View& rofMask, + const int transitionId, + const int fromLayer, + const int toLayer, + const typename ROFOverlapTable::View& rofOverlaps, + const typename ROFVertexLookupTable::View& vertexLUT, const int vertexId, const Vertex* vertices, const int* rofPV, - const int nVertices, const Cluster** clusters, std::vector nClusters, const int** ROFClusters, @@ -860,62 +602,59 @@ void countTrackletsInROFsHandler(const IndexTableUtils* utils, const int** clustersIndexTables, int** trackletsLUTs, gsl::span trackletsLUTsHost, - const int iteration, + const bool selectUPCVertices, const float NSigmaCut, - std::vector& phiCuts, + const typename TrackingTopology::View topology, + bounded_vector& transitionPhiCuts, const float resolutionPV, - std::vector& minRs, - std::vector& maxRs, - std::vector& resolutions, + std::array& minRs, + std::array& maxRs, + bounded_vector& resolutions, std::vector& radii, - std::vector& mulScatAng, - const int nBlocks, - const int nThreads) + bounded_vector& transitionMSAngles, + o2::its::ExternalAllocator* alloc, + gpu::Streams& streams) { - for (int iLayer = 0; iLayer < nLayers - 1; ++iLayer) { - gpu::computeLayerTrackletsMultiROFKernel<<>>( - utils, - multMask, - iLayer, - startROF, - endROF, - maxROF, - deltaROF, - vertices, - rofPV, - nVertices, - vertexId, - clusters, - ROFClusters, - usedClusters, - clustersIndexTables, - nullptr, - trackletsLUTs, - iteration, - NSigmaCut, - phiCuts[iLayer], - resolutionPV, - minRs[iLayer + 1], - maxRs[iLayer + 1], - resolutions[iLayer], - radii[iLayer + 1] - radii[iLayer], - mulScatAng[iLayer]); - gpu::cubExclusiveScanInPlace(trackletsLUTsHost[iLayer], nClusters[iLayer] + 1); - } + gpu::computeLayerTrackletsMultiROFKernel<<<60, 256, 0, streams[transitionId].get()>>>( + utils, + rofMask, + transitionId, + topology, + rofOverlaps, + vertexLUT, + vertices, + rofPV, + vertexId, + clusters, + ROFClusters, + usedClusters, + clustersIndexTables, + nullptr, + trackletsLUTs, + selectUPCVertices, + NSigmaCut, + transitionPhiCuts[transitionId], + resolutionPV, + minRs[toLayer], + maxRs[toLayer], + resolutions[fromLayer], + radii[toLayer] - radii[fromLayer], + transitionMSAngles[transitionId]); + auto nosync_policy = THRUST_NAMESPACE::par_nosync(gpu::TypedAllocator(alloc)).on(streams[transitionId].get()); + thrust::exclusive_scan(nosync_policy, trackletsLUTsHost[transitionId], trackletsLUTsHost[transitionId] + nClusters[fromLayer] + 1, trackletsLUTsHost[transitionId]); } -template -void computeTrackletsInROFsHandler(const IndexTableUtils* utils, - const uint8_t* multMask, - const int startROF, - const int endROF, - const int maxROF, - const int deltaROF, +template +void computeTrackletsInROFsHandler(const IndexTableUtils* utils, + const typename ROFMaskTable::View& rofMask, + const int transitionId, + const int fromLayer, + const int toLayer, + const typename ROFOverlapTable::View& rofOverlaps, + const typename ROFVertexLookupTable::View& vertexLUT, const int vertexId, const Vertex* vertices, const int* rofPV, - const int nVertices, const Cluster** clusters, std::vector nClusters, const int** ROFClusters, @@ -926,59 +665,60 @@ void computeTrackletsInROFsHandler(const IndexTableUtils* utils, gsl::span nTracklets, int** trackletsLUTs, gsl::span trackletsLUTsHost, - const int iteration, + const bool selectUPCVertices, const float NSigmaCut, - std::vector& phiCuts, + const typename TrackingTopology::View topology, + bounded_vector& transitionPhiCuts, const float resolutionPV, - std::vector& minRs, - std::vector& maxRs, - std::vector& resolutions, + std::array& minRs, + std::array& maxRs, + bounded_vector& resolutions, std::vector& radii, - std::vector& mulScatAng, - const int nBlocks, - const int nThreads) + bounded_vector& transitionMSAngles, + o2::its::ExternalAllocator* alloc, + gpu::Streams& streams) { - for (int iLayer = 0; iLayer < nLayers - 1; ++iLayer) { - gpu::computeLayerTrackletsMultiROFKernel<<>>(utils, - multMask, - iLayer, - startROF, - endROF, - maxROF, - deltaROF, - vertices, - rofPV, - nVertices, - vertexId, - clusters, - ROFClusters, - usedClusters, - clustersIndexTables, - tracklets, - trackletsLUTs, - iteration, - NSigmaCut, - phiCuts[iLayer], - resolutionPV, - minRs[iLayer + 1], - maxRs[iLayer + 1], - resolutions[iLayer], - radii[iLayer + 1] - radii[iLayer], - mulScatAng[iLayer]); - thrust::device_ptr tracklets_ptr(spanTracklets[iLayer]); - thrust::sort(thrust::device, tracklets_ptr, tracklets_ptr + nTracklets[iLayer], gpu::sort_tracklets()); - auto unique_end = thrust::unique(thrust::device, tracklets_ptr, tracklets_ptr + nTracklets[iLayer], gpu::equal_tracklets()); - nTracklets[iLayer] = unique_end - tracklets_ptr; - if (iLayer > 0) { - GPUChkErrS(cudaMemset(trackletsLUTsHost[iLayer], 0, nClusters[iLayer] * sizeof(int))); - gpu::compileTrackletsLookupTableKernel<<>>( - spanTracklets[iLayer], trackletsLUTsHost[iLayer], nTracklets[iLayer]); - gpu::cubExclusiveScanInPlace(trackletsLUTsHost[iLayer], nClusters[iLayer] + 1); - } + gpu::computeLayerTrackletsMultiROFKernel<<<60, 256, 0, streams[transitionId].get()>>>( + utils, + rofMask, + transitionId, + topology, + rofOverlaps, + vertexLUT, + vertices, + rofPV, + vertexId, + clusters, + ROFClusters, + usedClusters, + clustersIndexTables, + tracklets, + trackletsLUTs, + selectUPCVertices, + NSigmaCut, + transitionPhiCuts[transitionId], + resolutionPV, + minRs[toLayer], + maxRs[toLayer], + resolutions[fromLayer], + radii[toLayer] - radii[fromLayer], + transitionMSAngles[transitionId]); + thrust::device_ptr tracklets_ptr(spanTracklets[transitionId]); + auto nosync_policy = THRUST_NAMESPACE::par_nosync(gpu::TypedAllocator(alloc)).on(streams[transitionId].get()); + thrust::sort(nosync_policy, tracklets_ptr, tracklets_ptr + nTracklets[transitionId]); + auto unique_end = thrust::unique(nosync_policy, tracklets_ptr, tracklets_ptr + nTracklets[transitionId]); + nTracklets[transitionId] = unique_end - tracklets_ptr; + if (fromLayer > 0) { + GPUChkErrS(cudaMemsetAsync(trackletsLUTsHost[transitionId], 0, (nClusters[fromLayer] + 1) * sizeof(int), streams[transitionId].get())); + gpu::compileTrackletsLookupTableKernel<<<60, 256, 0, streams[transitionId].get()>>>( + spanTracklets[transitionId], + trackletsLUTsHost[transitionId], + nTracklets[transitionId]); + thrust::exclusive_scan(nosync_policy, trackletsLUTsHost[transitionId], trackletsLUTsHost[transitionId] + nClusters[fromLayer] + 1, trackletsLUTsHost[transitionId]); } } +template void countCellsHandler( const Cluster** sortedClusters, const Cluster** unsortedClusters, @@ -986,7 +726,8 @@ void countCellsHandler( Tracklet** tracklets, int** trackletsLUT, const int nTracklets, - const int layer, + const int cellTopologyId, + const typename TrackingTopology::View topology, CellSeed* cells, int** cellsLUTsArrayDevice, int* cellsLUTsHost, @@ -994,27 +735,32 @@ void countCellsHandler( const float maxChi2ClusterAttachment, const float cellDeltaTanLambdaSigma, const float nSigmaCut, - const int nBlocks, - const int nThreads) + const std::vector& layerxX0Host, + o2::its::ExternalAllocator* alloc, + gpu::Streams& streams) { - gpu::computeLayerCellsKernel<<>>( - sortedClusters, // const Cluster** - unsortedClusters, // const Cluster** - tfInfo, // const TrackingFrameInfo** - tracklets, // const Tracklets** - trackletsLUT, // const int** - nTracklets, // const int - layer, // const int - cells, // CellSeed* - cellsLUTsArrayDevice, // int** + thrust::device_vector layerxX0(layerxX0Host); + gpu::computeLayerCellsKernel<<<60, 256, 0, streams[cellTopologyId].get()>>>( + sortedClusters, // const Cluster** + unsortedClusters, // const Cluster** + tfInfo, // const TrackingFrameInfo** + tracklets, // const Tracklets** + trackletsLUT, // const int** + nTracklets, // const int + cellTopologyId, // const int + topology, + cells, // CellSeed* + cellsLUTsArrayDevice, // int** + thrust::raw_pointer_cast(&layerxX0[0]), bz, // const float maxChi2ClusterAttachment, // const float cellDeltaTanLambdaSigma, // const float nSigmaCut); // const float - gpu::cubExclusiveScanInPlace(cellsLUTsHost, nTracklets + 1); + auto nosync_policy = THRUST_NAMESPACE::par_nosync(gpu::TypedAllocator(alloc)).on(streams[cellTopologyId].get()); + thrust::exclusive_scan(nosync_policy, cellsLUTsHost, cellsLUTsHost + nTracklets + 1, cellsLUTsHost); } +template void computeCellsHandler( const Cluster** sortedClusters, const Cluster** unsortedClusters, @@ -1022,7 +768,8 @@ void computeCellsHandler( Tracklet** tracklets, int** trackletsLUT, const int nTracklets, - const int layer, + const int cellTopologyId, + const typename TrackingTopology::View topology, CellSeed* cells, int** cellsLUTsArrayDevice, int* cellsLUTsHost, @@ -1030,283 +777,370 @@ void computeCellsHandler( const float maxChi2ClusterAttachment, const float cellDeltaTanLambdaSigma, const float nSigmaCut, - const int nBlocks, - const int nThreads) + const std::vector& layerxX0Host, + gpu::Streams& streams) { - gpu::computeLayerCellsKernel<<>>( - sortedClusters, // const Cluster** - unsortedClusters, // const Cluster** - tfInfo, // const TrackingFrameInfo** - tracklets, // const Tracklets** - trackletsLUT, // const int** - nTracklets, // const int - layer, // const int - cells, // CellSeed* - cellsLUTsArrayDevice, // int** + thrust::device_vector layerxX0(layerxX0Host); + gpu::computeLayerCellsKernel<<<60, 256, 0, streams[cellTopologyId].get()>>>( + sortedClusters, // const Cluster** + unsortedClusters, // const Cluster** + tfInfo, // const TrackingFrameInfo** + tracklets, // const Tracklets** + trackletsLUT, // const int** + nTracklets, // const int + cellTopologyId, // const int + topology, + cells, // CellSeed* + cellsLUTsArrayDevice, // int** + thrust::raw_pointer_cast(&layerxX0[0]), bz, // const float maxChi2ClusterAttachment, // const float cellDeltaTanLambdaSigma, // const float nSigmaCut); // const float } -unsigned int countCellNeighboursHandler(CellSeed** cellsLayersDevice, - int* neighboursLUT, - int** cellsLUTs, - gpuPair* cellNeighbours, - int* neighboursIndexTable, - const float maxChi2ClusterAttachment, - const float bz, - const int layerIndex, - const unsigned int nCells, - const unsigned int nCellsNext, - const int maxCellNeighbours, - const int nBlocks, - const int nThreads) +template +void countCellNeighboursHandler(CellSeed** cellsLayersDevice, + int* neighboursCursor, + int** cellsLUTs, + const int sourceCellTopologyId, + const int targetCellTopologyId, + const float maxChi2ClusterAttachment, + const float bz, + const unsigned int nCells, + gpu::Stream& stream) { - gpu::computeLayerCellNeighboursKernel<<>>( + gpu::computeLayerCellNeighboursKernel<<<60, 256, 0, stream.get()>>>( cellsLayersDevice, - neighboursLUT, - neighboursIndexTable, + neighboursCursor, cellsLUTs, - cellNeighbours, + nullptr, + sourceCellTopologyId, + targetCellTopologyId, maxChi2ClusterAttachment, bz, - layerIndex, - nCells, - maxCellNeighbours); - - gpu::cubInclusiveScanInPlace(neighboursLUT, nCellsNext); - gpu::cubExclusiveScanInPlace(neighboursIndexTable, nCells + 1); - unsigned int nNeighbours; - GPUChkErrS(cudaMemcpy(&nNeighbours, &neighboursLUT[nCellsNext - 1], sizeof(unsigned int), cudaMemcpyDeviceToHost)); - return nNeighbours; + nCells); +} + +void scanCellNeighboursHandler(int* neighboursCursor, + int* neighboursLUT, + const unsigned int nCells, + o2::its::ExternalAllocator* alloc, + gpu::Stream& stream) +{ + auto nosync_policy = THRUST_NAMESPACE::par_nosync(gpu::TypedAllocator(alloc)).on(stream.get()); + thrust::exclusive_scan(nosync_policy, neighboursCursor, neighboursCursor + nCells + 1, neighboursCursor); + GPUChkErrS(cudaMemcpyAsync(neighboursLUT, neighboursCursor, (nCells + 1) * sizeof(int), cudaMemcpyDeviceToDevice, stream.get())); } +template void computeCellNeighboursHandler(CellSeed** cellsLayersDevice, - int* neighboursLUT, + int* neighboursCursor, int** cellsLUTs, - gpuPair* cellNeighbours, - int* neighboursIndexTable, + CellNeighbour* cellNeighbours, + const int sourceCellTopologyId, + const int targetCellTopologyId, const float maxChi2ClusterAttachment, const float bz, - const int layerIndex, const unsigned int nCells, - const unsigned int nCellsNext, - const int maxCellNeighbours, - const int nBlocks, - const int nThreads) + gpu::Stream& stream) { - - gpu::computeLayerCellNeighboursKernel<<>>( + gpu::computeLayerCellNeighboursKernel<<<60, 256, 0, stream.get()>>>( cellsLayersDevice, - neighboursLUT, - neighboursIndexTable, + neighboursCursor, cellsLUTs, cellNeighbours, + sourceCellTopologyId, + targetCellTopologyId, maxChi2ClusterAttachment, bz, - layerIndex, - nCells, - maxCellNeighbours); - GPUChkErrS(cudaPeekAtLastError()); - GPUChkErrS(cudaDeviceSynchronize()); + nCells); } int filterCellNeighboursHandler(gpuPair* cellNeighbourPairs, int* cellNeighbours, - unsigned int nNeigh) + unsigned int nNeigh, + gpu::Stream& stream, + o2::its::ExternalAllocator* allocator) { + auto nosync_policy = THRUST_NAMESPACE::par_nosync(gpu::TypedAllocator(allocator)).on(stream.get()); thrust::device_ptr> neighVectorPairs(cellNeighbourPairs); thrust::device_ptr validNeighs(cellNeighbours); - auto updatedEnd = thrust::remove_if(neighVectorPairs, neighVectorPairs + nNeigh, gpu::is_invalid_pair()); + auto updatedEnd = thrust::remove_if(nosync_policy, neighVectorPairs, neighVectorPairs + nNeigh, gpu::is_invalid_pair()); size_t newSize = updatedEnd - neighVectorPairs; - thrust::stable_sort(neighVectorPairs, neighVectorPairs + newSize, gpu::sort_by_second()); - thrust::transform(neighVectorPairs, neighVectorPairs + newSize, validNeighs, gpu::pair_to_first()); - + thrust::stable_sort(nosync_policy, neighVectorPairs, neighVectorPairs + newSize, gpu::sort_by_second()); + thrust::transform(nosync_policy, neighVectorPairs, neighVectorPairs + newSize, validNeighs, gpu::pair_to_first()); return newSize; } -template -void processNeighboursHandler(const int startLayer, - const int startLevel, +template +void processNeighboursHandler(const int startLevel, + const int defaultCellTopologyId, CellSeed** allCellSeeds, CellSeed* currentCellSeeds, - std::array& nCells, + const int* currentCellTopologyIds, + const int* currentCellIds, + const int* nCells, const unsigned char** usedClusters, - std::array& neighbours, - gsl::span neighboursDeviceLUTs, + CellNeighbour** neighbours, + int** neighboursDeviceLUTs, const TrackingFrameInfo** foundTrackingFrameInfo, - std::vector& seedsHost, + bounded_vector>& seedsHost, const float bz, const float maxChi2ClusterAttachment, const float maxChi2NDF, + const int maxHoles, + const int minTrackLength, + const LayerMask holeLayerMask, + const std::vector& layerxX0Host, const o2::base::Propagator* propagator, const o2::base::PropagatorF::MatCorrType matCorrType, - const int nBlocks, - const int nThreads) + o2::its::ExternalAllocator* alloc) { - thrust::device_vector foundSeedsTable(nCells[startLayer] + 1); // Shortcut: device_vector skips central memory management, we are relying on the contingency. - // TODO: fix this. - - gpu::processNeighboursKernel<<>>( - startLayer, + constexpr uint64_t Tag = qStr2Tag("ITS_PNH1"); + alloc->pushTagOnStack(Tag); + auto allocInt = gpu::TypedAllocator(alloc); + auto allocTrackSeed = gpu::TypedAllocator>(alloc); + thrust::device_vector layerxX0(layerxX0Host); + thrust::device_vector> foundSeedsTable(nCells[defaultCellTopologyId] + 1, 0, allocInt); + auto nosync_policy = THRUST_NAMESPACE::par_nosync(gpu::TypedAllocator(alloc)).on(gpu::Stream::DefaultStream); + + gpu::processNeighboursKernel<<<60, 256>>>( + defaultCellTopologyId, startLevel, allCellSeeds, currentCellSeeds, nullptr, - nCells[startLayer], + nullptr, + nCells[defaultCellTopologyId], + nullptr, nullptr, nullptr, thrust::raw_pointer_cast(&foundSeedsTable[0]), usedClusters, - neighbours[startLayer - 1], - neighboursDeviceLUTs[startLayer - 1], + neighbours, + neighboursDeviceLUTs, foundTrackingFrameInfo, + thrust::raw_pointer_cast(&layerxX0[0]), bz, maxChi2ClusterAttachment, propagator, matCorrType); - gpu::cubExclusiveScanInPlace(foundSeedsTable, nCells[startLayer] + 1); + thrust::exclusive_scan(nosync_policy, foundSeedsTable.begin(), foundSeedsTable.end(), foundSeedsTable.begin()); - thrust::device_vector updatedCellId(foundSeedsTable.back()); - thrust::device_vector updatedCellSeed(foundSeedsTable.back()); - gpu::processNeighboursKernel<<>>( - startLayer, + thrust::device_vector> updatedCellId(foundSeedsTable.back(), 0, allocInt); + thrust::device_vector> updatedCellTopologyId(foundSeedsTable.back(), 0, allocInt); + thrust::device_vector, gpu::TypedAllocator>> updatedCellSeed(foundSeedsTable.back(), allocTrackSeed); + gpu::processNeighboursKernel<<<60, 256>>>( + defaultCellTopologyId, startLevel, allCellSeeds, currentCellSeeds, nullptr, - nCells[startLayer], + nullptr, + nCells[defaultCellTopologyId], thrust::raw_pointer_cast(&updatedCellSeed[0]), thrust::raw_pointer_cast(&updatedCellId[0]), + thrust::raw_pointer_cast(&updatedCellTopologyId[0]), thrust::raw_pointer_cast(&foundSeedsTable[0]), usedClusters, - neighbours[startLayer - 1], - neighboursDeviceLUTs[startLayer - 1], + neighbours, + neighboursDeviceLUTs, foundTrackingFrameInfo, + thrust::raw_pointer_cast(&layerxX0[0]), bz, maxChi2ClusterAttachment, propagator, matCorrType); + GPUChkErrS(cudaStreamSynchronize(gpu::Stream::DefaultStream)); int level = startLevel; - thrust::device_vector lastCellId; - thrust::device_vector lastCellSeed; - for (int iLayer{startLayer - 1}; iLayer > 0 && level > 2; --iLayer) { + thrust::device_vector> lastCellId(allocInt); + thrust::device_vector> lastCellTopologyId(allocInt); + thrust::device_vector, gpu::TypedAllocator>> lastCellSeed(allocTrackSeed); + while (level > 2 && !updatedCellSeed.empty()) { lastCellSeed.swap(updatedCellSeed); lastCellId.swap(updatedCellId); - thrust::device_vector().swap(updatedCellSeed); - thrust::device_vector().swap(updatedCellId); + lastCellTopologyId.swap(updatedCellTopologyId); + thrust::device_vector, gpu::TypedAllocator>>(allocTrackSeed).swap(updatedCellSeed); + thrust::device_vector>(allocInt).swap(updatedCellId); + thrust::device_vector>(allocInt).swap(updatedCellTopologyId); auto lastCellSeedSize{lastCellSeed.size()}; foundSeedsTable.resize(lastCellSeedSize + 1); - thrust::fill(foundSeedsTable.begin(), foundSeedsTable.end(), 0); + thrust::fill(nosync_policy, foundSeedsTable.begin(), foundSeedsTable.end(), 0); - gpu::processNeighboursKernel<<>>( - iLayer, - --level, + --level; + gpu::processNeighboursKernel><<<60, 256>>>( + constants::UnusedIndex, + level, allCellSeeds, thrust::raw_pointer_cast(&lastCellSeed[0]), thrust::raw_pointer_cast(&lastCellId[0]), + thrust::raw_pointer_cast(&lastCellTopologyId[0]), lastCellSeedSize, nullptr, nullptr, + nullptr, thrust::raw_pointer_cast(&foundSeedsTable[0]), usedClusters, - neighbours[iLayer - 1], - neighboursDeviceLUTs[iLayer - 1], + neighbours, + neighboursDeviceLUTs, foundTrackingFrameInfo, + thrust::raw_pointer_cast(&layerxX0[0]), bz, maxChi2ClusterAttachment, propagator, matCorrType); - gpu::cubExclusiveScanInPlace(foundSeedsTable, foundSeedsTable.size()); + thrust::exclusive_scan(nosync_policy, foundSeedsTable.begin(), foundSeedsTable.end(), foundSeedsTable.begin()); auto foundSeeds{foundSeedsTable.back()}; updatedCellId.resize(foundSeeds); - thrust::fill(updatedCellId.begin(), updatedCellId.end(), 0); + thrust::fill(nosync_policy, updatedCellId.begin(), updatedCellId.end(), 0); + updatedCellTopologyId.resize(foundSeeds); + thrust::fill(nosync_policy, updatedCellTopologyId.begin(), updatedCellTopologyId.end(), 0); updatedCellSeed.resize(foundSeeds); - thrust::fill(updatedCellSeed.begin(), updatedCellSeed.end(), CellSeed()); + thrust::fill(nosync_policy, updatedCellSeed.begin(), updatedCellSeed.end(), TrackSeed()); - gpu::processNeighboursKernel<<>>( - iLayer, + gpu::processNeighboursKernel><<<60, 256>>>( + constants::UnusedIndex, level, allCellSeeds, thrust::raw_pointer_cast(&lastCellSeed[0]), thrust::raw_pointer_cast(&lastCellId[0]), + thrust::raw_pointer_cast(&lastCellTopologyId[0]), lastCellSeedSize, thrust::raw_pointer_cast(&updatedCellSeed[0]), thrust::raw_pointer_cast(&updatedCellId[0]), + thrust::raw_pointer_cast(&updatedCellTopologyId[0]), thrust::raw_pointer_cast(&foundSeedsTable[0]), usedClusters, - neighbours[iLayer - 1], - neighboursDeviceLUTs[iLayer - 1], + neighbours, + neighboursDeviceLUTs, foundTrackingFrameInfo, + thrust::raw_pointer_cast(&layerxX0[0]), bz, maxChi2ClusterAttachment, propagator, matCorrType); } - - thrust::device_vector outSeeds(updatedCellSeed.size()); - auto end = thrust::copy_if(updatedCellSeed.begin(), updatedCellSeed.end(), outSeeds.begin(), gpu::seed_selector(1.e3, maxChi2NDF * ((startLevel + 2) * 2 - 5))); + GPUChkErrS(cudaStreamSynchronize(gpu::Stream::DefaultStream)); + thrust::device_vector, gpu::TypedAllocator>> outSeeds(updatedCellSeed.size(), allocTrackSeed); + auto end = thrust::copy_if(nosync_policy, updatedCellSeed.begin(), updatedCellSeed.end(), outSeeds.begin(), gpu::seed_selector(1.e3, maxChi2NDF * ((startLevel + 2) * 2 - 5), maxHoles, minTrackLength, holeLayerMask)); auto s{end - outSeeds.begin()}; - std::vector outSeedsHost(s); - thrust::copy(outSeeds.begin(), outSeeds.begin() + s, outSeedsHost.begin()); - seedsHost.insert(seedsHost.end(), outSeedsHost.begin(), outSeedsHost.end()); + seedsHost.reserve(seedsHost.size() + s); + thrust::copy(outSeeds.begin(), outSeeds.begin() + s, std::back_inserter(seedsHost)); + alloc->popTagOffStack(Tag); } -void trackSeedHandler(CellSeed* trackSeeds, - const TrackingFrameInfo** foundTrackingFrameInfo, - o2::its::TrackITSExt* tracks, - std::vector& minPtsHost, - const unsigned int nSeeds, - const float bz, - const int startLevel, - float maxChi2ClusterAttachment, - float maxChi2NDF, - const o2::base::Propagator* propagator, - const o2::base::PropagatorF::MatCorrType matCorrType, - const int nBlocks, - const int nThreads) +template +void countTrackSeedHandler(TrackSeed* trackSeeds, + const TrackingFrameInfo** foundTrackingFrameInfo, + const Cluster** unsortedClusters, + int* seedLUT, + const std::vector& layerRadiiHost, + const std::vector& minPtsHost, + const std::vector& layerxX0Host, + const unsigned int nSeeds, + const float bz, + const int startLevel, + const float maxChi2ClusterAttachment, + const float maxChi2NDF, + const int reseedIfShorter, + const bool repeatRefitOut, + const bool shiftRefToCluster, + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType, + o2::its::ExternalAllocator* alloc) { + // TODO: the minPts&layerRadii is transfered twice + // we should allocate this in constant memory and stop these + // small transferes! thrust::device_vector minPts(minPtsHost); - gpu::fitTrackSeedsKernel<<>>( - trackSeeds, // CellSeed* - foundTrackingFrameInfo, // TrackingFrameInfo** - tracks, // TrackITSExt* - thrust::raw_pointer_cast(&minPts[0]), // const float* minPts, - nSeeds, // const unsigned int - bz, // const float - startLevel, // const int - maxChi2ClusterAttachment, // float - maxChi2NDF, // float - propagator, // const o2::base::Propagator* - matCorrType); // o2::base::PropagatorF::MatCorrType - thrust::device_ptr tr_ptr(tracks); + thrust::device_vector layerRadii(layerRadiiHost); + thrust::device_vector layerxX0(layerxX0Host); + gpu::fitTrackSeedsKernel<<<60, 256>>>( + trackSeeds, // CellSeed* + foundTrackingFrameInfo, // TrackingFrameInfo** + unsortedClusters, // Cluster** + nullptr, // TrackITSExt* + seedLUT, // int* + thrust::raw_pointer_cast(&layerRadii[0]), // const float* + thrust::raw_pointer_cast(&minPts[0]), // const float* + thrust::raw_pointer_cast(&layerxX0[0]), // const float* + nSeeds, // const unsigned int + bz, // const float + startLevel, // const int + maxChi2ClusterAttachment, // float + maxChi2NDF, // float + reseedIfShorter, // int + repeatRefitOut, // bool + shiftRefToCluster, // bool + propagator, // const o2::base::Propagator* + matCorrType); // o2::base::PropagatorF::MatCorrType + auto sync_policy = THRUST_NAMESPACE::par(gpu::TypedAllocator(alloc)); + thrust::exclusive_scan(sync_policy, seedLUT, seedLUT + nSeeds + 1, seedLUT); +} - thrust::sort(tr_ptr, tr_ptr + nSeeds, gpu::compare_track_chi2()); - GPUChkErrS(cudaPeekAtLastError()); - GPUChkErrS(cudaDeviceSynchronize()); +template +void computeTrackSeedHandler(TrackSeed* trackSeeds, + const TrackingFrameInfo** foundTrackingFrameInfo, + const Cluster** unsortedClusters, + o2::its::TrackITSExt* tracks, + const int* seedLUT, + const std::vector& layerRadiiHost, + const std::vector& minPtsHost, + const std::vector& layerxX0Host, + const unsigned int nSeeds, + const unsigned int nTracks, + const float bz, + const int startLevel, + const float maxChi2ClusterAttachment, + const float maxChi2NDF, + const int reseedIfShorter, + const bool repeatRefitOut, + const bool shiftRefToCluster, + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType, + o2::its::ExternalAllocator* alloc) +{ + thrust::device_vector minPts(minPtsHost); + thrust::device_vector layerRadii(layerRadiiHost); + thrust::device_vector layerxX0(layerxX0Host); + gpu::fitTrackSeedsKernel<<<60, 256>>>( + trackSeeds, // CellSeed* + foundTrackingFrameInfo, // TrackingFrameInfo** + unsortedClusters, // Cluster** + tracks, // TrackITSExt* + seedLUT, // const int* + thrust::raw_pointer_cast(&layerRadii[0]), // const float* + thrust::raw_pointer_cast(&minPts[0]), // const float* + thrust::raw_pointer_cast(&layerxX0[0]), // const float* + nSeeds, // const unsigned int + bz, // const float + startLevel, // const int + maxChi2ClusterAttachment, // float + maxChi2NDF, // float + reseedIfShorter, // int + repeatRefitOut, // bool + shiftRefToCluster, // bool + propagator, // const o2::base::Propagator* + matCorrType); // o2::base::PropagatorF::MatCorrType + auto sync_policy = THRUST_NAMESPACE::par(gpu::TypedAllocator(alloc)); + thrust::device_ptr tr_ptr(tracks); + thrust::sort(sync_policy, tr_ptr, tr_ptr + nTracks, gpu::compare_track_chi2()); } -template void countTrackletsInROFsHandler<7>(const IndexTableUtils* utils, - const uint8_t* multMask, - const int startROF, - const int endROF, - const int maxROF, - const int deltaROF, +/// Explicit instantiation of ITS2 handlers +template void countTrackletsInROFsHandler<7>(const IndexTableUtils<7>* utils, + const ROFMaskTable<7>::View& rofMask, + const int transitionId, + const int fromLayer, + const int toLayer, + const ROFOverlapTable<7>::View& rofOverlaps, + const ROFVertexLookupTable<7>::View& vertexLUT, const int vertexId, const Vertex* vertices, const int* rofPV, - const int nVertices, const Cluster** clusters, std::vector nClusters, const int** ROFClusters, @@ -1314,28 +1148,29 @@ template void countTrackletsInROFsHandler<7>(const IndexTableUtils* utils, const int** clustersIndexTables, int** trackletsLUTs, gsl::span trackletsLUTsHost, - const int iteration, + const bool selectUPCVertices, const float NSigmaCut, - std::vector& phiCuts, + const TrackingTopology<7>::View topology, + bounded_vector& transitionPhiCuts, const float resolutionPV, - std::vector& minRs, - std::vector& maxRs, - std::vector& resolutions, + std::array& minRs, + std::array& maxRs, + bounded_vector& resolutions, std::vector& radii, - std::vector& mulScatAng, - const int nBlocks, - const int nThreads); - -template void computeTrackletsInROFsHandler<7>(const IndexTableUtils* utils, - const uint8_t* multMask, - const int startROF, - const int endROF, - const int maxROF, - const int deltaROF, + bounded_vector& transitionMSAngles, + o2::its::ExternalAllocator* alloc, + gpu::Streams& streams); + +template void computeTrackletsInROFsHandler<7>(const IndexTableUtils<7>* utils, + const ROFMaskTable<7>::View& rofMask, + const int transitionId, + const int fromLayer, + const int toLayer, + const ROFOverlapTable<7>::View& rofOverlaps, + const ROFVertexLookupTable<7>::View& vertexLUT, const int vertexId, const Vertex* vertices, const int* rofPV, - const int nVertices, const Cluster** clusters, std::vector nClusters, const int** ROFClusters, @@ -1346,33 +1181,324 @@ template void computeTrackletsInROFsHandler<7>(const IndexTableUtils* utils, gsl::span nTracklets, int** trackletsLUTs, gsl::span trackletsLUTsHost, - const int iteration, + const bool selectUPCVertices, const float NSigmaCut, - std::vector& phiCuts, + const TrackingTopology<7>::View topology, + bounded_vector& transitionPhiCuts, const float resolutionPV, - std::vector& minRs, - std::vector& maxRs, - std::vector& resolutions, + std::array& minRs, + std::array& maxRs, + bounded_vector& resolutions, std::vector& radii, - std::vector& mulScatAng, - const int nBlocks, - const int nThreads); + bounded_vector& transitionMSAngles, + o2::its::ExternalAllocator* alloc, + gpu::Streams& streams); -template void processNeighboursHandler<7>(const int startLayer, - const int startLevel, +template void countCellsHandler<7>(const Cluster** sortedClusters, + const Cluster** unsortedClusters, + const TrackingFrameInfo** tfInfo, + Tracklet** tracklets, + int** trackletsLUT, + const int nTracklets, + const int cellTopologyId, + const TrackingTopology<7>::View topology, + CellSeed* cells, + int** cellsLUTsArrayDevice, + int* cellsLUTsHost, + const float bz, + const float maxChi2ClusterAttachment, + const float cellDeltaTanLambdaSigma, + const float nSigmaCut, + const std::vector& layerxX0Host, + o2::its::ExternalAllocator* alloc, + gpu::Streams& streams); + +template void computeCellsHandler<7>(const Cluster** sortedClusters, + const Cluster** unsortedClusters, + const TrackingFrameInfo** tfInfo, + Tracklet** tracklets, + int** trackletsLUT, + const int nTracklets, + const int cellTopologyId, + const TrackingTopology<7>::View topology, + CellSeed* cells, + int** cellsLUTsArrayDevice, + int* cellsLUTsHost, + const float bz, + const float maxChi2ClusterAttachment, + const float cellDeltaTanLambdaSigma, + const float nSigmaCut, + const std::vector& layerxX0Host, + gpu::Streams& streams); + +template void countCellNeighboursHandler<7>(CellSeed** cellsLayersDevice, + int* neighboursCursor, + int** cellsLUTs, + const int sourceCellTopologyId, + const int targetCellTopologyId, + const float maxChi2ClusterAttachment, + const float bz, + const unsigned int nCells, + gpu::Stream& stream); + +template void computeCellNeighboursHandler<7>(CellSeed** cellsLayersDevice, + int* neighboursCursor, + int** cellsLUTs, + CellNeighbour* cellNeighbours, + const int sourceCellTopologyId, + const int targetCellTopologyId, + const float maxChi2ClusterAttachment, + const float bz, + const unsigned int nCells, + gpu::Stream& stream); + +template void processNeighboursHandler<7>(const int startLevel, + const int defaultCellTopologyId, CellSeed** allCellSeeds, CellSeed* currentCellSeeds, - std::array& nCells, + const int* currentCellTopologyIds, + const int* currentCellIds, + const int* nCells, const unsigned char** usedClusters, - std::array& neighbours, - gsl::span neighboursDeviceLUTs, + CellNeighbour** neighbours, + int** neighboursDeviceLUTs, const TrackingFrameInfo** foundTrackingFrameInfo, - std::vector& seedsHost, + bounded_vector>& seedsHost, const float bz, const float maxChi2ClusterAttachment, const float maxChi2NDF, + const int maxHoles, + const int minTrackLength, + const LayerMask holeLayerMask, + const std::vector& layerxX0Host, const o2::base::Propagator* propagator, const o2::base::PropagatorF::MatCorrType matCorrType, - const int nBlocks, - const int nThreads); + o2::its::ExternalAllocator* alloc); + +template void countTrackSeedHandler(TrackSeed<7>* trackSeeds, + const TrackingFrameInfo** foundTrackingFrameInfo, + const Cluster** unsortedClusters, + int* seedLUT, + const std::vector& layerRadiiHost, + const std::vector& minPtsHost, + const std::vector& layerxX0Host, + const unsigned int nSeeds, + const float bz, + const int startLevel, + const float maxChi2ClusterAttachment, + const float maxChi2NDF, + const int reseedIfShorter, + const bool repeatRefitOut, + const bool shiftRefToCluster, + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType, + o2::its::ExternalAllocator* alloc); + +template void computeTrackSeedHandler(TrackSeed<7>* trackSeeds, + const TrackingFrameInfo** foundTrackingFrameInfo, + const Cluster** unsortedClusters, + o2::its::TrackITSExt* tracks, + const int* seedLUT, + const std::vector& layerRadiiHost, + const std::vector& minPtsHost, + const std::vector& layerxX0Host, + const unsigned int nSeeds, + const unsigned int nTracks, + const float bz, + const int startLevel, + const float maxChi2ClusterAttachment, + const float maxChi2NDF, + const int reseedIfShorter, + const bool repeatRefitOut, + const bool shiftRefToCluster, + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType, + o2::its::ExternalAllocator* alloc); + +/// Explicit instantiation of ALICE3 handlers +#ifdef ENABLE_UPGRADES +template void countTrackletsInROFsHandler<11>(const IndexTableUtils<11>* utils, + const ROFMaskTable<11>::View& rofMask, + const int transitionId, + const int fromLayer, + const int toLayer, + const ROFOverlapTable<11>::View& rofOverlaps, + const ROFVertexLookupTable<11>::View& vertexLUT, + const int vertexId, + const Vertex* vertices, + const int* rofPV, + const Cluster** clusters, + std::vector nClusters, + const int** ROFClusters, + const unsigned char** usedClusters, + const int** clustersIndexTables, + int** trackletsLUTs, + gsl::span trackletsLUTsHost, + const bool selectUPCVertices, + const float NSigmaCut, + const TrackingTopology<11>::View topology, + bounded_vector& transitionPhiCuts, + const float resolutionPV, + std::array& minRs, + std::array& maxRs, + bounded_vector& resolutions, + std::vector& radii, + bounded_vector& transitionMSAngles, + o2::its::ExternalAllocator* alloc, + gpu::Streams& streams); + +template void computeTrackletsInROFsHandler<11>(const IndexTableUtils<11>* utils, + const ROFMaskTable<11>::View& rofMask, + const int transitionId, + const int fromLayer, + const int toLayer, + const ROFOverlapTable<11>::View& rofOverlaps, + const ROFVertexLookupTable<11>::View& vertexLUT, + const int vertexId, + const Vertex* vertices, + const int* rofPV, + const Cluster** clusters, + std::vector nClusters, + const int** ROFClusters, + const unsigned char** usedClusters, + const int** clustersIndexTables, + Tracklet** tracklets, + gsl::span spanTracklets, + gsl::span nTracklets, + int** trackletsLUTs, + gsl::span trackletsLUTsHost, + const bool selectUPCVertices, + const float NSigmaCut, + const TrackingTopology<11>::View topology, + bounded_vector& transitionPhiCuts, + const float resolutionPV, + std::array& minRs, + std::array& maxRs, + bounded_vector& resolutions, + std::vector& radii, + bounded_vector& transitionMSAngles, + o2::its::ExternalAllocator* alloc, + gpu::Streams& streams); + +template void countCellsHandler<11>(const Cluster** sortedClusters, + const Cluster** unsortedClusters, + const TrackingFrameInfo** tfInfo, + Tracklet** tracklets, + int** trackletsLUT, + const int nTracklets, + const int cellTopologyId, + const TrackingTopology<11>::View topology, + CellSeed* cells, + int** cellsLUTsArrayDevice, + int* cellsLUTsHost, + const float bz, + const float maxChi2ClusterAttachment, + const float cellDeltaTanLambdaSigma, + const float nSigmaCut, + const std::vector& layerxX0Host, + o2::its::ExternalAllocator* alloc, + gpu::Streams& streams); + +template void computeCellsHandler<11>(const Cluster** sortedClusters, + const Cluster** unsortedClusters, + const TrackingFrameInfo** tfInfo, + Tracklet** tracklets, + int** trackletsLUT, + const int nTracklets, + const int cellTopologyId, + const TrackingTopology<11>::View topology, + CellSeed* cells, + int** cellsLUTsArrayDevice, + int* cellsLUTsHost, + const float bz, + const float maxChi2ClusterAttachment, + const float cellDeltaTanLambdaSigma, + const float nSigmaCut, + const std::vector& layerxX0Host, + gpu::Streams& streams); + +template void countCellNeighboursHandler<11>(CellSeed** cellsLayersDevice, + int* neighboursCursor, + int** cellsLUTs, + const int sourceCellTopologyId, + const int targetCellTopologyId, + const float maxChi2ClusterAttachment, + const float bz, + const unsigned int nCells, + gpu::Stream& stream); + +template void computeCellNeighboursHandler<11>(CellSeed** cellsLayersDevice, + int* neighboursCursor, + int** cellsLUTs, + CellNeighbour* cellNeighbours, + const int sourceCellTopologyId, + const int targetCellTopologyId, + const float maxChi2ClusterAttachment, + const float bz, + const unsigned int nCells, + gpu::Stream& stream); + +template void processNeighboursHandler<11>(const int startLevel, + const int defaultCellTopologyId, + CellSeed** allCellSeeds, + CellSeed* currentCellSeeds, + const int* currentCellTopologyIds, + const int* currentCellIds, + const int* nCells, + const unsigned char** usedClusters, + CellNeighbour** neighbours, + int** neighboursDeviceLUTs, + const TrackingFrameInfo** foundTrackingFrameInfo, + bounded_vector>& seedsHost, + const float bz, + const float maxChi2ClusterAttachment, + const float maxChi2NDF, + const int maxHoles, + const int minTrackLength, + const LayerMask holeLayerMask, + const std::vector& layerxX0Host, + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType, + o2::its::ExternalAllocator* alloc); + +template void countTrackSeedHandler(TrackSeed<11>* trackSeeds, + const TrackingFrameInfo** foundTrackingFrameInfo, + const Cluster** unsortedClusters, + int* seedLUT, + const std::vector& layerRadiiHost, + const std::vector& minPtsHost, + const std::vector& layerxX0Host, + const unsigned int nSeeds, + const float bz, + const int startLevel, + const float maxChi2ClusterAttachment, + const float maxChi2NDF, + const int reseedIfShorter, + const bool repeatRefitOut, + const bool shiftRefToCluster, + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType, + o2::its::ExternalAllocator* alloc); + +template void computeTrackSeedHandler(TrackSeed<11>* trackSeeds, + const TrackingFrameInfo** foundTrackingFrameInfo, + const Cluster** unsortedClusters, + o2::its::TrackITSExt* tracks, + const int* seedLUT, + const std::vector& layerRadiiHost, + const std::vector& minPtsHost, + const std::vector& layerxX0Host, + const unsigned int nSeeds, + const unsigned int nTracks, + const float bz, + const int startLevel, + const float maxChi2ClusterAttachment, + const float maxChi2NDF, + const int reseedIfShorter, + const bool repeatRefitOut, + const bool shiftRefToCluster, + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType, + o2::its::ExternalAllocator* alloc); +#endif } // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexerTraitsGPU.cxx b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexerTraitsGPU.cxx deleted file mode 100644 index f630d2cdec76a..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexerTraitsGPU.cxx +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -/// \author matteo.concas@cern.ch - -#include -#include -#include -#include -#include -#include - -#ifdef VTX_DEBUG -#include "TTree.h" -#include "TFile.h" -#endif - -#include "ITStrackingGPU/VertexingKernels.h" -#include "ITStrackingGPU/VertexerTraitsGPU.h" - -namespace o2::its -{ -VertexerTraitsGPU::VertexerTraitsGPU() -{ - setIsGPU(true); -} - -void VertexerTraitsGPU::initialise(const TrackingParameters& trackingParams, const int iteration) -{ - mTimeFrameGPU->initialise(0, trackingParams, 3, &mIndexTableUtils, &mTfGPUParams); -} - -void VertexerTraitsGPU::updateVertexingParameters(const std::vector& vrtPar, const TimeFrameGPUParameters& tfPar) -{ - mVrtParams = vrtPar; - mTfGPUParams = tfPar; - mIndexTableUtils.setTrackingParameters(vrtPar[0]); - for (auto& par : mVrtParams) { - par.phiSpan = static_cast(std::ceil(mIndexTableUtils.getNphiBins() * par.phiCut / constants::math::TwoPi)); - par.zSpan = static_cast(std::ceil(par.zCut * mIndexTableUtils.getInverseZCoordinate(0))); - } -} - -void VertexerTraitsGPU::computeTracklets(const int iteration) -{ - if (!mTimeFrameGPU->getClusters().size()) { - return; - } - // std::vector threads(mTimeFrameGPU->getNChunks()); - // for (int chunkId{0}; chunkId < mTimeFrameGPU->getNChunks(); ++chunkId) { - // int rofPerChunk{mTimeFrameGPU->mNrof / (int)mTimeFrameGPU->getNChunks()}; - // mTimeFrameGPU->getVerticesInChunks()[chunkId].clear(); - // mTimeFrameGPU->getNVerticesInChunks()[chunkId].clear(); - // mTimeFrameGPU->getLabelsInChunks()[chunkId].clear(); - // auto doVertexReconstruction = [&, chunkId, rofPerChunk]() -> void { - // auto offset = chunkId * rofPerChunk; - // auto maxROF = offset + rofPerChunk; - // while (offset < maxROF) { - // auto rofs = mTimeFrameGPU->loadChunkData(chunkId, offset, maxROF); - // RANGE("chunk_gpu_vertexing", 1); - // // gpu::GpuTimer timer{offset, mTimeFrameGPU->getStream(chunkId).get()}; - // // timer.Start("vtTrackletFinder"); - // gpu::trackleterKernelMultipleRof<<getStream(chunkId).get()>>>( - // mTimeFrameGPU->getChunk(chunkId).getDeviceClusters(0), // const Cluster* clustersNextLayer, // 0 2 - // mTimeFrameGPU->getChunk(chunkId).getDeviceClusters(1), // const Cluster* clustersCurrentLayer, // 1 1 - // mTimeFrameGPU->getDeviceROframesClusters(0), // const int* sizeNextLClusters, - // mTimeFrameGPU->getDeviceROframesClusters(1), // const int* sizeCurrentLClusters, - // mTimeFrameGPU->getChunk(chunkId).getDeviceIndexTables(0), // const int* nextIndexTables, - // mTimeFrameGPU->getChunk(chunkId).getDeviceTracklets(0), // Tracklet* Tracklets, - // mTimeFrameGPU->getChunk(chunkId).getDeviceNTrackletCluster(0), // int* foundTracklets, - // mTimeFrameGPU->getDeviceIndexTableUtils(), // const IndexTableUtils* utils, - // offset, // const unsigned int startRofId, - // rofs, // const unsigned int rofSize, - // mVrtParams.phiCut, // const float phiCut, - // mVrtParams.maxTrackletsPerCluster); // const size_t maxTrackletsPerCluster = 1e2 - - // gpu::trackleterKernelMultipleRof<<getStream(chunkId).get()>>>( - // mTimeFrameGPU->getChunk(chunkId).getDeviceClusters(2), // const Cluster* clustersNextLayer, // 0 2 - // mTimeFrameGPU->getChunk(chunkId).getDeviceClusters(1), // const Cluster* clustersCurrentLayer, // 1 1 - // mTimeFrameGPU->getDeviceROframesClusters(2), // const int* sizeNextLClusters, - // mTimeFrameGPU->getDeviceROframesClusters(1), // const int* sizeCurrentLClusters, - // mTimeFrameGPU->getChunk(chunkId).getDeviceIndexTables(2), // const int* nextIndexTables, - // mTimeFrameGPU->getChunk(chunkId).getDeviceTracklets(1), // Tracklet* Tracklets, - // mTimeFrameGPU->getChunk(chunkId).getDeviceNTrackletCluster(1), // int* foundTracklets, - // mTimeFrameGPU->getDeviceIndexTableUtils(), // const IndexTableUtils* utils, - // offset, // const unsigned int startRofId, - // rofs, // const unsigned int rofSize, - // mVrtParams.phiCut, // const float phiCut, - // mVrtParams.maxTrackletsPerCluster); // const size_t maxTrackletsPerCluster = 1e2 - - // gpu::trackletSelectionKernelMultipleRof<<getStream(chunkId).get()>>>( - // mTimeFrameGPU->getChunk(chunkId).getDeviceClusters(0), // const Cluster* clusters0, // Clusters on layer 0 - // mTimeFrameGPU->getChunk(chunkId).getDeviceClusters(1), // const Cluster* clusters1, // Clusters on layer 1 - // mTimeFrameGPU->getDeviceROframesClusters(0), // const int* sizeClustersL0, // Number of clusters on layer 0 per ROF - // mTimeFrameGPU->getDeviceROframesClusters(1), // const int* sizeClustersL1, // Number of clusters on layer 1 per ROF - // mTimeFrameGPU->getChunk(chunkId).getDeviceTracklets(0), // Tracklet* tracklets01, // Tracklets on layer 0-1 - // mTimeFrameGPU->getChunk(chunkId).getDeviceTracklets(1), // Tracklet* tracklets12, // Tracklets on layer 1-2 - // mTimeFrameGPU->getChunk(chunkId).getDeviceNTrackletCluster(0), // const int* nFoundTracklets01, // Number of tracklets found on layers 0-1 - // mTimeFrameGPU->getChunk(chunkId).getDeviceNTrackletCluster(1), // const int* nFoundTracklet12, // Number of tracklets found on layers 1-2 - // mTimeFrameGPU->getChunk(chunkId).getDeviceUsedTracklets(), // unsigned char* usedTracklets, // Used tracklets - // mTimeFrameGPU->getChunk(chunkId).getDeviceLines(), // Line* lines, // Lines - // mTimeFrameGPU->getChunk(chunkId).getDeviceNFoundLines(), // int* nFoundLines, // Number of found lines - // mTimeFrameGPU->getChunk(chunkId).getDeviceNExclusiveFoundLines(), // int* nExclusiveFoundLines, // Number of found lines exclusive scan - // offset, // const unsigned int startRofId, // Starting ROF ID - // rofs, // const unsigned int rofSize, // Number of ROFs to consider - // mVrtParams.maxTrackletsPerCluster, // const int maxTrackletsPerCluster = 1e2, // Maximum number of tracklets per cluster - // mVrtParams.tanLambdaCut, // const float tanLambdaCut = 0.025f, // Cut on tan lambda - // mVrtParams.phiCut); // const float phiCut = 0.002f) // Cut on phi - - // discardResult(cub::DeviceScan::ExclusiveSum(mTimeFrameGPU->getChunk(chunkId).getDeviceCUBTmpBuffer(), - // mTimeFrameGPU->getChunk(chunkId).getTimeFrameGPUParameters()->tmpCUBBufferSize, - // mTimeFrameGPU->getChunk(chunkId).getDeviceNFoundLines(), - // mTimeFrameGPU->getChunk(chunkId).getDeviceNExclusiveFoundLines(), - // mTimeFrameGPU->getTotalClustersPerROFrange(offset, rofs, 1), - // mTimeFrameGPU->getStream(chunkId).get())); - - // // Reset used tracklets - // checkGPUError(cudaMemsetAsync(mTimeFrameGPU->getChunk(chunkId).getDeviceUsedTracklets(), - // false, - // sizeof(unsigned char) * mVrtParams.maxTrackletsPerCluster * mTimeFrameGPU->getTotalClustersPerROFrange(offset, rofs, 1), - // mTimeFrameGPU->getStream(chunkId).get()), - // __FILE__, __LINE__); - - // gpu::trackletSelectionKernelMultipleRof<<getStream(chunkId).get()>>>( - // mTimeFrameGPU->getChunk(chunkId).getDeviceClusters(0), // const Cluster* clusters0, // Clusters on layer 0 - // mTimeFrameGPU->getChunk(chunkId).getDeviceClusters(1), // const Cluster* clusters1, // Clusters on layer 1 - // mTimeFrameGPU->getDeviceROframesClusters(0), // const int* sizeClustersL0, // Number of clusters on layer 0 per ROF - // mTimeFrameGPU->getDeviceROframesClusters(1), // const int* sizeClustersL1, // Number of clusters on layer 1 per ROF - // mTimeFrameGPU->getChunk(chunkId).getDeviceTracklets(0), // Tracklet* tracklets01, // Tracklets on layer 0-1 - // mTimeFrameGPU->getChunk(chunkId).getDeviceTracklets(1), // Tracklet* tracklets12, // Tracklets on layer 1-2 - // mTimeFrameGPU->getChunk(chunkId).getDeviceNTrackletCluster(0), // const int* nFoundTracklets01, // Number of tracklets found on layers 0-1 - // mTimeFrameGPU->getChunk(chunkId).getDeviceNTrackletCluster(1), // const int* nFoundTracklet12, // Number of tracklets found on layers 1-2 - // mTimeFrameGPU->getChunk(chunkId).getDeviceUsedTracklets(), // unsigned char* usedTracklets, // Used tracklets - // mTimeFrameGPU->getChunk(chunkId).getDeviceLines(), // Line* lines, // Lines - // mTimeFrameGPU->getChunk(chunkId).getDeviceNFoundLines(), // int* nFoundLines, // Number of found lines - // mTimeFrameGPU->getChunk(chunkId).getDeviceNExclusiveFoundLines(), // int* nExclusiveFoundLines, // Number of found lines exclusive scan - // offset, // const unsigned int startRofId, // Starting ROF ID - // rofs, // const unsigned int rofSize, // Number of ROFs to consider - // mVrtParams.maxTrackletsPerCluster, // const int maxTrackletsPerCluster = 1e2, // Maximum number of tracklets per cluster - // mVrtParams.tanLambdaCut, // const float tanLambdaCut = 0.025f, // Cut on tan lambda - // mVrtParams.phiCut); // const float phiCut = 0.002f) // Cut on phi - - // int nClusters = mTimeFrameGPU->getTotalClustersPerROFrange(offset, rofs, 1); - // int lastFoundLines; - // std::vector exclusiveFoundLinesHost(nClusters + 1); - - // // Obtain whole exclusive sum including nCluster+1 element (nCluster+1)th element is the total number of found lines. - // checkGPUError(cudaMemcpyAsync(exclusiveFoundLinesHost.data(), mTimeFrameGPU->getChunk(chunkId).getDeviceNExclusiveFoundLines(), (nClusters) * sizeof(int), cudaMemcpyDeviceToHost, mTimeFrameGPU->getStream(chunkId).get())); - // checkGPUError(cudaMemcpyAsync(&lastFoundLines, mTimeFrameGPU->getChunk(chunkId).getDeviceNFoundLines() + nClusters - 1, sizeof(int), cudaMemcpyDeviceToHost, mTimeFrameGPU->getStream(chunkId).get())); - // exclusiveFoundLinesHost[nClusters] = exclusiveFoundLinesHost[nClusters - 1] + lastFoundLines; - - // std::vector lines(exclusiveFoundLinesHost[nClusters]); - - // checkGPUError(cudaMemcpyAsync(lines.data(), mTimeFrameGPU->getChunk(chunkId).getDeviceLines(), sizeof(Line) * lines.size(), cudaMemcpyDeviceToHost, mTimeFrameGPU->getStream(chunkId).get())); - // checkGPUError(cudaStreamSynchronize(mTimeFrameGPU->getStream(chunkId).get())); - - // // Compute vertices - // std::vector clusterLines; - // std::vector usedLines; - // for (int rofId{0}; rofId < rofs; ++rofId) { - // auto rof = offset + rofId; - // auto clustersL1offsetRof = mTimeFrameGPU->getROframeClusters(1)[rof] - mTimeFrameGPU->getROframeClusters(1)[offset]; // starting cluster offset for this ROF - // auto nClustersL1Rof = mTimeFrameGPU->getROframeClusters(1)[rof + 1] - mTimeFrameGPU->getROframeClusters(1)[rof]; // number of clusters for this ROF - // auto linesOffsetRof = exclusiveFoundLinesHost[clustersL1offsetRof]; // starting line offset for this ROF - // auto nLinesRof = exclusiveFoundLinesHost[clustersL1offsetRof + nClustersL1Rof] - linesOffsetRof; - // gsl::span linesInRof(lines.data() + linesOffsetRof, static_cast::size_type>(nLinesRof)); - - // usedLines.resize(linesInRof.size(), false); - // usedLines.assign(linesInRof.size(), false); - // clusterLines.clear(); - // clusterLines.reserve(nClustersL1Rof); - // computeVerticesInRof(rof, - // linesInRof, - // usedLines, - // clusterLines, - // mTimeFrameGPU->getBeamXY(), - // mTimeFrameGPU->getVerticesInChunks()[chunkId], - // mTimeFrameGPU->getNVerticesInChunks()[chunkId], - // mTimeFrameGPU, - // mTimeFrameGPU->hasMCinformation() ? &mTimeFrameGPU->getLabelsInChunks()[chunkId] : nullptr); - // } - // offset += rofs; - // } - // }; - // // Do work - // threads[chunkId] = std::thread(doVertexReconstruction); - // } - // for (auto& thread : threads) { - // thread.join(); - // } - // for (int chunkId{0}; chunkId < mTimeFrameGPU->getNChunks(); ++chunkId) { - // int start{0}; - // for (int rofId{0}; rofId < mTimeFrameGPU->getNVerticesInChunks()[chunkId].size(); ++rofId) { - // gsl::span rofVerts{mTimeFrameGPU->getVerticesInChunks()[chunkId].data() + start, static_cast::size_type>(mTimeFrameGPU->getNVerticesInChunks()[chunkId][rofId])}; - // mTimeFrameGPU->addPrimaryVertices(rofVerts); - // if (mTimeFrameGPU->hasMCinformation()) { - // mTimeFrameGPU->getVerticesLabels().emplace_back(); - // // TODO: add MC labels - // } - // start += mTimeFrameGPU->getNVerticesInChunks()[chunkId][rofId]; - // } - // } - // mTimeFrameGPU->wipe(3); - // } -} - -void VertexerTraitsGPU::computeTrackletMatching(const int iteration) -{ -} - -void VertexerTraitsGPU::computeVertices(const int iteration) -{ -} - -void VertexerTraitsGPU::computeVerticesHist() -{ -} - -VertexerTraits* createVertexerTraitsGPU() -{ - return new VertexerTraitsGPU; -} -} // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexingKernels.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexingKernels.cu deleted file mode 100644 index 3aab0624ef556..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexingKernels.cu +++ /dev/null @@ -1,580 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// - -#include -#include - -#include "ITStrackingGPU/VertexingKernels.h" -#include "GPUCommonHelpers.h" - -namespace o2 -{ -namespace its -{ -using constants::its::VertexerHistogramVolume; -using constants::math::TwoPi; -using math_utils::getNormalizedPhi; -using namespace constants::its2; - -namespace gpu -{ -template -void trackletFinderHandler(const Cluster* clustersNextLayer, // 0 2 - const Cluster* clustersCurrentLayer, // 1 1 - const int* sizeNextLClusters, - const int* sizeCurrentLClusters, - const int* nextIndexTables, - Tracklet* Tracklets, - int* foundTracklets, - const IndexTableUtils* utils, - const unsigned int startRofId, - const unsigned int rofSize, - const float phiCut, - const unsigned int maxTrackletsPerCluster, - const int nBlocks, - const int nThreads) -{ - gpu::trackleterKernelMultipleRof<<>>( - clustersNextLayer, // const Cluster* clustersNextLayer, // 0 2 - clustersCurrentLayer, // const Cluster* clustersCurrentLayer, // 1 1 - sizeNextLClusters, // const int* sizeNextLClusters, - sizeCurrentLClusters, // const int* sizeCurrentLClusters, - nextIndexTables, // const int* nextIndexTables, - Tracklets, // Tracklet* Tracklets, - foundTracklets, // int* foundTracklets, - utils, // const IndexTableUtils* utils, - startRofId, // const unsigned int startRofId, - rofSize, // const unsigned int rofSize, - phiCut, // const float phiCut, - maxTrackletsPerCluster); // const unsigned int maxTrackletsPerCluster = 1e2 -} -/* -GPUd() float smallestAngleDifference(float a, float b) -{ - float diff = fmod(b - a + constants::math::Pi, constants::math::TwoPi) - constants::math::Pi; - return (diff < -constants::math::Pi) ? diff + constants::math::TwoPi : ((diff > constants::math::Pi) ? diff - constants::math::TwoPi : diff); -} - -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)}; -} - -template -GPUd() void printOnThread(const unsigned int tId, const char* str, Args... args) -{ - if (blockIdx.x * blockDim.x + threadIdx.x == tId) { - printf(str, args...); - } -} - -template -GPUd() void printOnBlock(const unsigned int bId, const char* str, Args... args) -{ - if (blockIdx.x == bId && threadIdx.x == 0) { - printf(str, args...); - } -} - -GPUg() void printBufferOnThread(const int* v, unsigned int size, const int len = 150, const unsigned int tId = 0) -{ - if (blockIdx.x * blockDim.x + threadIdx.x == tId) { - for (int i{0}; i < size; ++i) { - if (!(i % len)) { - printf("\n start: ===>%d/%d\t", i, (int)size); - } - printf("%d\t", v[i]); - } - printf("\n"); - } -} - -GPUg() void printBufferOnThreadF(const float* v, unsigned int size, const unsigned int tId = 0) -{ - if (blockIdx.x * blockDim.x + threadIdx.x == tId) { - printf("vector :"); - for (int i{0}; i < size; ++i) { - printf("%.9f\t", v[i]); - } - printf("\n"); - } -} - -GPUg() void resetTrackletsKernel(Tracklet* tracklets, const int nTracklets) -{ - for (int iCurrentLayerClusterIndex = blockIdx.x * blockDim.x + threadIdx.x; iCurrentLayerClusterIndex < nTracklets; iCurrentLayerClusterIndex += blockDim.x * gridDim.x) { - new (tracklets + iCurrentLayerClusterIndex) Tracklet{}; - } -} - -GPUg() void dumpFoundTrackletsKernel(const Tracklet* tracklets, const int* nTracklet, const unsigned int nClustersMiddleLayer, const int maxTrackletsPerCluster) -{ - for (int iCurrentLayerClusterIndex = blockIdx.x * blockDim.x + threadIdx.x; iCurrentLayerClusterIndex < nClustersMiddleLayer; iCurrentLayerClusterIndex += blockDim.x * gridDim.x) { - const int stride{iCurrentLayerClusterIndex * maxTrackletsPerCluster}; - for (int iTracklet{0}; iTracklet < nTracklet[iCurrentLayerClusterIndex]; ++iTracklet) { - auto& t = tracklets[stride + iTracklet]; - t.dump(); - } - } -} - -GPUg() void dumpMaximaKernel(const cub::KeyValuePair* tmpVertexBins, 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", - tmpVertexBins[0].value, tmpVertexBins[0].key, - tmpVertexBins[1].value, tmpVertexBins[1].key, - tmpVertexBins[2].value, tmpVertexBins[2].key); - } -} - -template -GPUg() void trackleterKernelSingleRof( - const Cluster* clustersNextLayer, // 0 2 - const Cluster* clustersCurrentLayer, // 1 1 - const int sizeNextLClusters, - const int sizeCurrentLClusters, - const int* indexTableNext, - const float phiCut, - Tracklet* Tracklets, - int* foundTracklets, - const IndexTableUtils* utils, - const short rofId, - const unsigned int maxTrackletsPerCluster = 1e2) -{ - const int phiBins{utils->getNphiBins()}; - const int zBins{utils->getNzBins()}; - // loop on layer1 clusters - for (int iCurrentLayerClusterIndex = blockIdx.x * blockDim.x + threadIdx.x; iCurrentLayerClusterIndex < sizeCurrentLClusters; iCurrentLayerClusterIndex += blockDim.x * gridDim.x) { - if (iCurrentLayerClusterIndex < sizeCurrentLClusters) { - unsigned int storedTracklets{0}; - const unsigned int stride{iCurrentLayerClusterIndex * maxTrackletsPerCluster}; - const Cluster& currentCluster = clustersCurrentLayer[iCurrentLayerClusterIndex]; - const int4 selectedBinsRect{VertexerTraits::getBinsRect(currentCluster, (int)Mode, 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) { - phiBinsNum += phiBins; - } - // loop on phi bins next layer - for (unsigned int iPhiBin{(unsigned int)selectedBinsRect.y}, iPhiCount{0}; iPhiCount < (unsigned int)phiBinsNum; iPhiBin = ++iPhiBin == phiBins ? 0 : iPhiBin, iPhiCount++) { - 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 < sizeNextLClusters; ++iNextLayerClusterIndex) { - const Cluster& nextCluster = clustersNextLayer[iNextLayerClusterIndex]; - if (o2::gpu::GPUCommonMath::Abs(currentCluster.phi - nextCluster.phi) < phiCut) { - if (storedTracklets < maxTrackletsPerCluster) { - if constexpr (Mode == TrackletMode::Layer0Layer1) { - new (Tracklets + stride + storedTracklets) Tracklet{iNextLayerClusterIndex, iCurrentLayerClusterIndex, nextCluster, currentCluster, rofId, rofId}; - } else { - new (Tracklets + stride + storedTracklets) Tracklet{iCurrentLayerClusterIndex, iNextLayerClusterIndex, currentCluster, nextCluster, rofId, rofId}; - } - ++storedTracklets; - } - } - } - } - } - foundTracklets[iCurrentLayerClusterIndex] = storedTracklets; - if (storedTracklets >= maxTrackletsPerCluster) { - printf("gpu tracklet finder: some lines will be left behind for cluster %d. valid: %u max: %zu\n", iCurrentLayerClusterIndex, storedTracklets, maxTrackletsPerCluster); - } - } - } -} - -template -GPUg() void trackleterKernelMultipleRof( - const Cluster* clustersNextLayer, // 0 2 - const Cluster* clustersCurrentLayer, // 1 1 - const int* sizeNextLClusters, - const int* sizeCurrentLClusters, - const int* nextIndexTables, - Tracklet* Tracklets, - int* foundTracklets, - const IndexTableUtils* utils, - const short startRofId, - const short rofSize, - const float phiCut, - const unsigned int maxTrackletsPerCluster = 1e2) -{ - const int phiBins{utils->getNphiBins()}; - const int zBins{utils->getNzBins()}; - for (auto iRof{blockIdx.x}; iRof < rofSize; iRof += gridDim.x) { - short rof = static_cast(iRof) + startRofId; - auto* clustersNextLayerRof = clustersNextLayer + (sizeNextLClusters[rof] - sizeNextLClusters[startRofId]); - auto* clustersCurrentLayerRof = clustersCurrentLayer + (sizeCurrentLClusters[rof] - sizeCurrentLClusters[startRofId]); - auto nClustersNextLayerRof = sizeNextLClusters[rof + 1] - sizeNextLClusters[rof]; - auto nClustersCurrentLayerRof = sizeCurrentLClusters[rof + 1] - sizeCurrentLClusters[rof]; - auto* indexTableNextRof = nextIndexTables + iRof * (phiBins * zBins + 1); - auto* TrackletsRof = Tracklets + (sizeCurrentLClusters[rof] - sizeCurrentLClusters[startRofId]) * maxTrackletsPerCluster; - auto* foundTrackletsRof = foundTracklets + (sizeCurrentLClusters[rof] - sizeCurrentLClusters[startRofId]); - - // single rof loop on layer1 clusters - for (int iCurrentLayerClusterIndex = threadIdx.x; iCurrentLayerClusterIndex < nClustersCurrentLayerRof; iCurrentLayerClusterIndex += blockDim.x) { - unsigned int storedTracklets{0}; - const unsigned int stride{iCurrentLayerClusterIndex * maxTrackletsPerCluster}; - const Cluster& currentCluster = clustersCurrentLayerRof[iCurrentLayerClusterIndex]; - const int4 selectedBinsRect{VertexerTraits::getBinsRect(currentCluster, (int)Mode, 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) { - phiBinsNum += phiBins; - } - // loop on phi bins next layer - for (unsigned int iPhiBin{(unsigned int)selectedBinsRect.y}, iPhiCount{0}; iPhiCount < (unsigned int)phiBinsNum; iPhiBin = ++iPhiBin == phiBins ? 0 : iPhiBin, iPhiCount++) { - const int firstBinIndex{utils->getBinIndex(selectedBinsRect.x, iPhiBin)}; - const int firstRowClusterIndex{indexTableNextRof[firstBinIndex]}; - const int maxRowClusterIndex{indexTableNextRof[firstBinIndex + zBins]}; - // loop on clusters next layer - for (int iNextLayerClusterIndex{firstRowClusterIndex}; iNextLayerClusterIndex < maxRowClusterIndex && iNextLayerClusterIndex < nClustersNextLayerRof; ++iNextLayerClusterIndex) { - const Cluster& nextCluster = clustersNextLayerRof[iNextLayerClusterIndex]; - if (o2::gpu::GPUCommonMath::Abs(smallestAngleDifference(currentCluster.phi, nextCluster.phi)) < phiCut) { - if (storedTracklets < maxTrackletsPerCluster) { - if constexpr (Mode == TrackletMode::Layer0Layer1) { - new (TrackletsRof + stride + storedTracklets) Tracklet{iNextLayerClusterIndex, iCurrentLayerClusterIndex, nextCluster, currentCluster, rof, rof}; - } else { - new (TrackletsRof + stride + storedTracklets) Tracklet{iCurrentLayerClusterIndex, iNextLayerClusterIndex, currentCluster, nextCluster, rof, rof}; - } - ++storedTracklets; - } - } - } - } - } - foundTrackletsRof[iCurrentLayerClusterIndex] = storedTracklets; - // if (storedTracklets >= maxTrackletsPerCluster && storedTracklets - maxTrackletsPerCluster < 5) { - // printf("gpu tracklet finder: some lines will be left behind for cluster %d in rof: %d. valid: %u max: %lu (suppressing after 5 msgs)\n", iCurrentLayerClusterIndex, rof, storedTracklets, maxTrackletsPerCluster); - // } - } - } -} - -template -GPUg() void trackletSelectionKernelSingleRof( - const Cluster* clusters0, - const Cluster* clusters1, - const unsigned int nClustersMiddleLayer, - Tracklet* tracklets01, - Tracklet* tracklets12, - const int* nFoundTracklet01, - const int* nFoundTracklet12, - unsigned char* usedTracklets, - Line* lines, - int* nFoundLines, - int* nExclusiveFoundLines, - const int maxTrackletsPerCluster = 1e2, - const float tanLambdaCut = 0.025f, - const float phiCut = 0.002f) -{ - for (int iCurrentLayerClusterIndex = blockIdx.x * blockDim.x + threadIdx.x; iCurrentLayerClusterIndex < nClustersMiddleLayer; iCurrentLayerClusterIndex += blockDim.x * gridDim.x) { - const int stride{iCurrentLayerClusterIndex * maxTrackletsPerCluster}; - int validTracklets{0}; - for (int iTracklet12{0}; iTracklet12 < nFoundTracklet12[iCurrentLayerClusterIndex]; ++iTracklet12) { - for (int iTracklet01{0}; iTracklet01 < nFoundTracklet01[iCurrentLayerClusterIndex] && validTracklets < maxTrackletsPerCluster; ++iTracklet01) { - const float deltaTanLambda{o2::gpu::GPUCommonMath::Abs(tracklets01[stride + iTracklet01].tanLambda - tracklets12[stride + iTracklet12].tanLambda)}; - const float deltaPhi{o2::gpu::GPUCommonMath::Abs(smallestAngleDifference(tracklets01[stride + iTracklet01].phi, tracklets12[stride + iTracklet12].phi))}; - if (!usedTracklets[stride + iTracklet01] && deltaTanLambda < tanLambdaCut && deltaPhi < phiCut && validTracklets != maxTrackletsPerCluster) { - usedTracklets[stride + iTracklet01] = true; - if constexpr (!initRun) { - new (lines + nExclusiveFoundLines[iCurrentLayerClusterIndex] + validTracklets) Line{tracklets01[stride + iTracklet01], clusters0, clusters1}; - } - ++validTracklets; - } - } - } - if constexpr (initRun) { - nFoundLines[iCurrentLayerClusterIndex] = validTracklets; - if (validTracklets >= maxTrackletsPerCluster) { - printf("gpu tracklet selection: some lines will be left behind for cluster %d. valid: %d max: %d\n", iCurrentLayerClusterIndex, validTracklets, maxTrackletsPerCluster); - } - } - } -} - -template -GPUg() void trackletSelectionKernelMultipleRof( - const Cluster* clusters0, // Clusters on layer 0 - const Cluster* clusters1, // Clusters on layer 1 - const int* sizeClustersL0, // Number of clusters on layer 0 per ROF - const int* sizeClustersL1, // Number of clusters on layer 1 per ROF - Tracklet* tracklets01, // Tracklets on layer 0-1 - Tracklet* tracklets12, // Tracklets on layer 1-2 - const int* nFoundTracklets01, // Number of tracklets found on layers 0-1 - const int* nFoundTracklets12, // Number of tracklets found on layers 1-2 - unsigned char* usedTracklets, // Used tracklets - Line* lines, // Lines - int* nFoundLines, // Number of found lines - int* nExclusiveFoundLines, // Number of found lines exclusive scan - const unsigned int startRofId, // Starting ROF ID - const unsigned int rofSize, // Number of ROFs to consider - const int maxTrackletsPerCluster = 1e2, // Maximum number of tracklets per cluster - const float tanLambdaCut = 0.025f, // Cut on tan lambda - const float phiCut = 0.002f) // Cut on phi -{ - for (unsigned int iRof{blockIdx.x}; iRof < rofSize; iRof += gridDim.x) { - auto rof = iRof + startRofId; - auto* clustersL0Rof = clusters0 + (sizeClustersL0[rof] - sizeClustersL0[startRofId]); - auto clustersL1offsetRof = sizeClustersL1[rof] - sizeClustersL1[startRofId]; - auto* clustersL1Rof = clusters1 + clustersL1offsetRof; - auto nClustersL1Rof = sizeClustersL1[rof + 1] - sizeClustersL1[rof]; - auto* tracklets01Rof = tracklets01 + clustersL1offsetRof * maxTrackletsPerCluster; - auto* tracklets12Rof = tracklets12 + clustersL1offsetRof * maxTrackletsPerCluster; - auto* foundTracklets01Rof = nFoundTracklets01 + clustersL1offsetRof; - auto* foundTracklets12Rof = nFoundTracklets12 + clustersL1offsetRof; - auto* usedTrackletsRof = usedTracklets + clustersL1offsetRof * maxTrackletsPerCluster; - auto* foundLinesRof = nFoundLines + clustersL1offsetRof; - int* nExclusiveFoundLinesRof = nullptr; - if constexpr (!initRun) { - nExclusiveFoundLinesRof = nExclusiveFoundLines + clustersL1offsetRof; - } - for (int iClusterIndexLayer1 = threadIdx.x; iClusterIndexLayer1 < nClustersL1Rof; iClusterIndexLayer1 += blockDim.x) { - const int stride{iClusterIndexLayer1 * maxTrackletsPerCluster}; - int validTracklets{0}; - for (int iTracklet12{0}; iTracklet12 < foundTracklets12Rof[iClusterIndexLayer1]; ++iTracklet12) { - for (int iTracklet01{0}; iTracklet01 < foundTracklets01Rof[iClusterIndexLayer1] && validTracklets < maxTrackletsPerCluster; ++iTracklet01) { - const float deltaTanLambda{o2::gpu::GPUCommonMath::Abs(tracklets01Rof[stride + iTracklet01].tanLambda - tracklets12Rof[stride + iTracklet12].tanLambda)}; - const float deltaPhi{o2::gpu::GPUCommonMath::Abs(tracklets01Rof[stride + iTracklet01].phi - tracklets12Rof[stride + iTracklet12].phi)}; - if (!usedTrackletsRof[stride + iTracklet01] && deltaTanLambda < tanLambdaCut && deltaPhi < phiCut && validTracklets != maxTrackletsPerCluster) { - usedTrackletsRof[stride + iTracklet01] = true; - if constexpr (!initRun) { - new (lines + nExclusiveFoundLinesRof[iClusterIndexLayer1] + validTracklets) Line{tracklets01Rof[stride + iTracklet01], clustersL0Rof, clustersL1Rof}; - } - ++validTracklets; - } - } - } - if constexpr (initRun) { - foundLinesRof[iClusterIndexLayer1] = validTracklets; - // if (validTracklets >= maxTrackletsPerCluster) { - // printf("gpu tracklet selection: some lines will be left behind for cluster %d. valid: %d max: %d\n", iClusterIndexLayer1, validTracklets, maxTrackletsPerCluster); - // } - } - } - } // rof loop -} - -GPUg() void lineClustererMultipleRof( - const int* sizeClustersL1, // Number of clusters on layer 1 per ROF - Line* lines, // Lines - int* nFoundLines, // Number of found lines - int* nExclusiveFoundLines, // Number of found lines exclusive scan - int* clusteredLines, // Clustered lines - const unsigned int startRofId, // Starting ROF ID - const unsigned int rofSize, // Number of ROFs to consider // Number of found lines exclusive scan - const float pairCut) // Selection on line pairs -{ - for (unsigned int iRof{threadIdx.x}; iRof < rofSize; iRof += blockDim.x) { - auto rof = iRof + startRofId; - auto clustersL1offsetRof = sizeClustersL1[rof] - sizeClustersL1[startRofId]; // starting cluster offset for this ROF - auto nClustersL1Rof = sizeClustersL1[rof + 1] - sizeClustersL1[rof]; // number of clusters for this ROF - auto linesOffsetRof = nExclusiveFoundLines[clustersL1offsetRof]; // starting line offset for this ROF - // auto* foundLinesRof = nFoundLines + clustersL1offsetRof; - auto nLinesRof = nExclusiveFoundLines[clustersL1offsetRof + nClustersL1Rof] - linesOffsetRof; - // printf("rof: %d -> %d lines.\n", rof, nLinesRof); - for (int iLine1 = 0; iLine1 < nLinesRof; ++iLine1) { - auto absLine1Index = nExclusiveFoundLines[clustersL1offsetRof] + iLine1; - if (clusteredLines[absLine1Index] > -1) { - continue; - } - for (int iLine2 = iLine1 + 1; iLine2 < nLinesRof; ++iLine2) { - auto absLine2Index = nExclusiveFoundLines[clustersL1offsetRof] + iLine2; - if (clusteredLines[absLine2Index] > -1) { - continue; - } - - if (Line::getDCA(lines[absLine1Index], lines[absLine2Index]) < pairCut) { - ClusterLinesGPU tmpClus{lines[absLine1Index], lines[absLine2Index]}; - float tmpVertex[3]; - tmpVertex[0] = tmpClus.getVertex()[0]; - tmpVertex[1] = tmpClus.getVertex()[1]; - tmpVertex[2] = tmpClus.getVertex()[2]; - if (tmpVertex[0] * tmpVertex[0] + tmpVertex[1] * tmpVertex[1] > 4.f) { // outside the beampipe, skip it - break; - } - clusteredLines[absLine1Index] = iLine1; // We set local index of first line to contribute, so we can retrieve the cluster later - clusteredLines[absLine2Index] = iLine1; - for (int iLine3 = 0; iLine3 < nLinesRof; ++iLine3) { - auto absLine3Index = nExclusiveFoundLines[clustersL1offsetRof] + iLine3; - if (clusteredLines[absLine3Index] > -1) { - continue; - } - if (Line::getDistanceFromPoint(lines[absLine3Index], tmpVertex) < pairCut) { - clusteredLines[absLine3Index] = iLine1; - } - } - break; - } - } - } - } // rof loop -} - -GPUg() void computeCentroidsKernel( - Line* lines, - int* nFoundLines, - int* nExclusiveFoundLines, - const unsigned int nClustersMiddleLayer, - float* centroids, - const float lowHistX, - const float highHistX, - const float lowHistY, - const float highHistY, - const float pairCut) -{ - const int nLines = nExclusiveFoundLines[nClustersMiddleLayer - 1] + nFoundLines[nClustersMiddleLayer - 1]; - const 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; - // All unique pairs - if (iSecondLine <= iFirstLine) { - iFirstLine = nLines - iFirstLine - 2; - iSecondLine = nLines - iSecondLine - 1; - } - if (Line::getDCA(lines[iFirstLine], lines[iSecondLine]) < pairCut) { - ClusterLinesGPU cluster{lines[iFirstLine], lines[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]); - centroids[2 * currentThreadIndex] = cluster.getVertex()[0]; - centroids[2 * currentThreadIndex + 1] = cluster.getVertex()[1]; - } else { - // write values outside the histogram boundaries, - // default behaviour is not to have them added to histogram later - // (writing zeroes would be problematic) - centroids[2 * currentThreadIndex] = 2 * lowHistX; - centroids[2 * currentThreadIndex + 1] = 2 * lowHistY; - } - } else { - // write values outside the histogram boundaries, - // default behaviour is not to have them added to histogram later - // (writing zeroes would be problematic) - centroids[2 * currentThreadIndex] = 2 * highHistX; - centroids[2 * currentThreadIndex + 1] = 2 * highHistY; - } - } -} - -GPUg() void computeZCentroidsKernel( - const int nLines, - const cub::KeyValuePair* tmpVtX, - float* beamPosition, - Line* lines, - float* centroids, - const int* histX, // X - const float lowHistX, - const float binSizeHistX, - const int nBinsHistX, - const int* histY, // Y - const float lowHistY, - const float binSizeHistY, - const int nBinsHistY, - const float lowHistZ, // Z - const float pairCut, - const int binOpeningX, - const int binOpeningY) -{ - for (unsigned int currentThreadIndex = blockIdx.x * blockDim.x + threadIdx.x; currentThreadIndex < nLines; currentThreadIndex += blockDim.x * gridDim.x) { - if (tmpVtX[0].value || tmpVtX[1].value) { - float tmpX{lowHistX + tmpVtX[0].key * binSizeHistX + binSizeHistX / 2}; - int sumWX{tmpVtX[0].value}; - float wX{tmpX * tmpVtX[0].value}; - for (int iBin{o2::gpu::GPUCommonMath::Max(0, tmpVtX[0].key - binOpeningX)}; iBin < o2::gpu::GPUCommonMath::Min(tmpVtX[0].key + binOpeningX + 1, nBinsHistX - 1); ++iBin) { - if (iBin != tmpVtX[0].key) { - wX += (lowHistX + iBin * binSizeHistX + binSizeHistX / 2) * histX[iBin]; - sumWX += histX[iBin]; - } - } - float tmpY{lowHistY + tmpVtX[1].key * binSizeHistY + binSizeHistY / 2}; - int sumWY{tmpVtX[1].value}; - float wY{tmpY * tmpVtX[1].value}; - for (int iBin{o2::gpu::GPUCommonMath::Max(0, tmpVtX[1].key - binOpeningY)}; iBin < o2::gpu::GPUCommonMath::Min(tmpVtX[1].key + binOpeningY + 1, nBinsHistY - 1); ++iBin) { - if (iBin != tmpVtX[1].key) { - wY += (lowHistY + iBin * binSizeHistY + binSizeHistY / 2) * histY[iBin]; - sumWY += histY[iBin]; - } - } - beamPosition[0] = wX / sumWX; - beamPosition[1] = wY / sumWY; - float mockBeamPoint1[3] = {beamPosition[0], beamPosition[1], -1}; // get two points laying at different z, to create line object - float mockBeamPoint2[3] = {beamPosition[0], beamPosition[1], 1}; - Line pseudoBeam = {mockBeamPoint1, mockBeamPoint2}; - if (Line::getDCA(lines[currentThreadIndex], pseudoBeam) < pairCut) { - ClusterLinesGPU cluster{lines[currentThreadIndex], pseudoBeam}; - centroids[currentThreadIndex] = cluster.getVertex()[2]; - } else { - centroids[currentThreadIndex] = 2 * lowHistZ; - } - } - } -} - -GPUg() void computeVertexKernel( - cub::KeyValuePair* tmpVertexBins, - int* histZ, // Z - const float lowHistZ, - const float binSizeHistZ, - const int nBinsHistZ, - Vertex* vertices, - float* beamPosition, - const int vertIndex, - const int minContributors, - const int binOpeningZ) -{ - for (unsigned int currentThreadIndex = blockIdx.x * blockDim.x + threadIdx.x; currentThreadIndex < binOpeningZ; currentThreadIndex += blockDim.x * gridDim.x) { - if (currentThreadIndex == 0) { - if (tmpVertexBins[2].value > 1 && (tmpVertexBins[0].value || tmpVertexBins[1].value)) { - float z{lowHistZ + tmpVertexBins[2].key * binSizeHistZ + binSizeHistZ / 2}; - float ex{0.f}; - float ey{0.f}; - float ez{0.f}; - int sumWZ{tmpVertexBins[2].value}; - float wZ{z * tmpVertexBins[2].value}; - for (int iBin{o2::gpu::GPUCommonMath::Max(0, tmpVertexBins[2].key - binOpeningZ)}; iBin < o2::gpu::GPUCommonMath::Min(tmpVertexBins[2].key + binOpeningZ + 1, nBinsHistZ - 1); ++iBin) { - if (iBin != tmpVertexBins[2].key) { - wZ += (lowHistZ + iBin * binSizeHistZ + binSizeHistZ / 2) * histZ[iBin]; - sumWZ += histZ[iBin]; - } - histZ[iBin] = 0; - } - if (sumWZ > minContributors || vertIndex == 0) { - new (vertices + vertIndex) Vertex{o2::math_utils::Point3D(beamPosition[0], beamPosition[1], wZ / sumWZ), o2::gpu::gpustd::array{ex, 0, ey, 0, 0, ez}, static_cast(sumWZ), 0}; - } else { - new (vertices + vertIndex) Vertex{}; - } - } else { - new (vertices + vertIndex) Vertex{}; - } - } - } -} -*/ -} // namespace gpu -} // namespace its -} // namespace o2 \ 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 index cc43b6845a714..e28fe04c06772 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/hip/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/tracking/GPU/hip/CMakeLists.txt @@ -12,14 +12,13 @@ if(HIP_ENABLED) message(STATUS "Building ITS HIP tracker") set(CMAKE_HIP_FLAGS "${CMAKE_HIP_FLAGS} -fgpu-rdc") + # set(CMAKE_HIP_FLAGS "${CMAKE_HIP_FLAGS} -O0 -g -ggdb -fno-inline -fno-omit-frame-pointer -D__HIP_ENABLE_DEVICE_ASSERT__") + # add_compile_definitions(ITS_MEASURE_GPU_TIME) + # add_compile_definitions(ITS_GPU_LOG) o2_add_hipified_library(ITStrackingHIP - SOURCES ../cuda/ClusterLinesGPU.cu - ../cuda/TimeFrameGPU.cu + SOURCES ../cuda/TimeFrameGPU.cu ../cuda/TrackerTraitsGPU.cxx - ../cuda/TracerGPU.cu ../cuda/TrackingKernels.cu - ../cuda/VertexingKernels.cu - ../cuda/VertexerTraitsGPU.cxx PUBLIC_INCLUDE_DIRECTORIES ../ PUBLIC_LINK_LIBRARIES O2::ITStracking O2::GPUTracking @@ -28,4 +27,4 @@ if(HIP_ENABLED) hip::host PRIVATE_LINK_LIBRARIES O2::GPUTrackingHIPExternalProvider TARGETVARNAME targetName) -endif() \ No newline at end of file +endif() diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ArrayUtils.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ArrayUtils.h deleted file mode 100644 index 971ae6a7fe83a..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ArrayUtils.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file ArrayUtils.h -/// \brief -/// - -#ifndef TRACKINGITSU_INCLUDE_ARRAYUTILS_H_ -#define TRACKINGITSU_INCLUDE_ARRAYUTILS_H_ - -#include -#include -#include - -namespace o2 -{ -namespace its -{ -namespace CA -{ - -namespace ArrayUtils -{ -template -constexpr std::array fillArray(Initializer, std::index_sequence); -template -constexpr std::array fillArray(Initializer); -} // namespace ArrayUtils - -template -constexpr std::array ArrayUtils::fillArray(Initializer initializer, std::index_sequence) -{ - return std::array{{initializer(Is)...}}; -} - -template -constexpr std::array ArrayUtils::fillArray(Initializer initializer) -{ - return ArrayUtils::fillArray(initializer, std::make_index_sequence{}); -} -} // namespace CA -} // namespace its -} // namespace o2 - -#endif /* TRACKINGITSU_INCLUDE_ARRAYUTILS_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/BoundedAllocator.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/BoundedAllocator.h new file mode 100644 index 0000000000000..3a03e9d145907 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/BoundedAllocator.h @@ -0,0 +1,287 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file BoundedAllocator.h +/// \brief +/// + +#ifndef TRACKINGITSU_INCLUDE_BOUNDEDALLOCATOR_H_ +#define TRACKINGITSU_INCLUDE_BOUNDEDALLOCATOR_H_ + +#include +#include +#include +#include +#include + +#if !defined(__HIPCC__) && !defined(__CUDACC__) +#include +#include +#include "GPUCommonLogger.h" +#endif +#include "ITStracking/ExternalAllocator.h" +#include "ITStracking/Constants.h" + +namespace o2::its +{ + +// #define BOUNDED_MR_STATS +class BoundedMemoryResource final : public std::pmr::memory_resource +{ + public: + class MemoryLimitExceeded final : public std::bad_alloc + { + public: + MemoryLimitExceeded(size_t attempted, size_t used, size_t max) + { + char buf[256]; + if (attempted != 0) { + (void)snprintf(buf, sizeof(buf), "Reached set memory limit (attempted: %zu, used: %zu, max: %zu)", attempted, used, max); + } else { + (void)snprintf(buf, sizeof(buf), "New set maximum below current used (newMax: %zu, used: %zu)", max, used); + } + mMsg = buf; + } + const char* what() const noexcept final { return mMsg.c_str(); } + + private: + std::string mMsg; + }; + + BoundedMemoryResource(size_t maxBytes = std::numeric_limits::max(), + std::pmr::memory_resource* upstream = std::pmr::get_default_resource()) + : mMaxMemory(maxBytes), mUpstream(upstream) {} + + BoundedMemoryResource(ExternalAllocator* alloc, + size_t maxBytes = std::numeric_limits::max()) + : mMaxMemory(maxBytes), + mAdaptor(std::make_unique(alloc)), + mUpstream(mAdaptor.get()) {} + + void* do_allocate(size_t bytes, size_t alignment) final + { + size_t new_used{0}; + size_t current_used{mUsedMemory.load(std::memory_order_relaxed)}; + do { + new_used = current_used + bytes; + if (new_used > mMaxMemory.load(std::memory_order_relaxed)) { + mCountThrow.fetch_add(1, std::memory_order_relaxed); + throw MemoryLimitExceeded(new_used, current_used, + mMaxMemory.load(std::memory_order_relaxed)); + } + } while (!mUsedMemory.compare_exchange_weak(current_used, new_used, + std::memory_order_acq_rel, + std::memory_order_relaxed)); + + void* p{nullptr}; + try { + p = mUpstream->allocate(bytes, alignment); + } catch (...) { + mUsedMemory.fetch_sub(bytes, std::memory_order_relaxed); +#ifdef BOUNDED_MR_STATS + mStats.upstreamFailures.fetch_add(1, std::memory_order_relaxed); +#endif + throw; + } + +#ifdef BOUNDED_MR_STATS + size_t peak = mStats.peak.load(std::memory_order_relaxed); + while (new_used > peak && + !mStats.peak.compare_exchange_weak(peak, new_used, + std::memory_order_relaxed)) { + } + mStats.live.fetch_add(1, std::memory_order_relaxed); + mStats.nAlloc.fetch_add(1, std::memory_order_relaxed); + mStats.totalAlloc.fetch_add(bytes, std::memory_order_relaxed); + + size_t ma = mStats.maxAlign.load(std::memory_order_relaxed); + while (alignment > ma && !mStats.maxAlign.compare_exchange_weak(ma, alignment, std::memory_order_relaxed)) { + } +#endif + return p; + } + + void do_deallocate(void* p, size_t bytes, size_t alignment) final + { + mUpstream->deallocate(p, bytes, alignment); + mUsedMemory.fetch_sub(bytes, std::memory_order_relaxed); +#ifdef BOUNDED_MR_STATS + mStats.live.fetch_sub(1, std::memory_order_relaxed); + mStats.nFree.fetch_add(1, std::memory_order_relaxed); + mStats.totalFreed.fetch_add(bytes, std::memory_order_relaxed); +#endif + } + + bool do_is_equal(const std::pmr::memory_resource& other) const noexcept final + { + return this == &other; + } + + [[nodiscard]] size_t getUsedMemory() const noexcept + { + return mUsedMemory.load(std::memory_order_relaxed); + } + [[nodiscard]] size_t getMaxMemory() const noexcept + { + return mMaxMemory.load(std::memory_order_relaxed); + } + [[nodiscard]] size_t getThrowCount() const noexcept + { + return mCountThrow.load(std::memory_order_relaxed); + } + + void setMaxMemory(size_t max) + { + size_t current = mMaxMemory.load(std::memory_order_relaxed); + if (max == current) { + return; + } + for (;;) { + size_t used = mUsedMemory.load(std::memory_order_acquire); + if (used > max) { + mCountThrow.fetch_add(1, std::memory_order_relaxed); + throw MemoryLimitExceeded(0, used, max); + } + if (mMaxMemory.compare_exchange_weak(current, max, + std::memory_order_release, + std::memory_order_relaxed)) { + return; + } + if (current == max) { + return; + } + } + } + +#if !defined(__HIPCC__) && !defined(__CUDACC__) + std::string asString() const + { + const auto throw_ = mCountThrow.load(std::memory_order_relaxed); + const auto used = static_cast(mUsedMemory.load(std::memory_order_relaxed)); + const auto maxm = mMaxMemory.load(std::memory_order_relaxed); + std::string ret; + if (maxm == std::numeric_limits::max()) { + ret += std::format("maxthrow={} maxmem=unbounded used={:.2f} GB", throw_, used / constants::GB); + } else { + ret += std::format("maxthrow={} maxmem={:.2f} GB used={:.2f} GB ({:.2f}%)", throw_, (double)maxm / constants::GB, used / constants::GB, 100.0 * used / (double)maxm); + } +#ifdef BOUNDED_MR_STATS + ret += std::format(" peak={:.2f} GB live={} nAlloc={} nFree={} totalAlloc={:.2f} GB totalFreed={:.2f} GB maxAlign={} upstreamFail={}", + (float)mStats.peak.load(std::memory_order_relaxed) / constants::GB, + mStats.live.load(std::memory_order_relaxed), + mStats.nAlloc.load(std::memory_order_relaxed), + mStats.nFree.load(std::memory_order_relaxed), + (float)mStats.totalAlloc.load(std::memory_order_relaxed) / constants::GB, + (float)mStats.totalFreed.load(std::memory_order_relaxed) / constants::GB, + mStats.maxAlign.load(std::memory_order_relaxed), + mStats.upstreamFailures.load(std::memory_order_relaxed)); +#endif + return ret; + } + + void print() const + { + LOGP(info, "{}", asString()); + } +#endif + + private: + std::atomic mMaxMemory{std::numeric_limits::max()}; + std::atomic mCountThrow{0}; + std::atomic mUsedMemory{0}; + std::unique_ptr mAdaptor{nullptr}; + std::pmr::memory_resource* mUpstream{nullptr}; + +#ifdef BOUNDED_MR_STATS + struct Stats { + std::atomic peak{0}; + std::atomic live{0}; + std::atomic nAlloc{0}; + std::atomic nFree{0}; + std::atomic totalAlloc{0}; + std::atomic totalFreed{0}; + std::atomic maxAlign{0}; + std::atomic upstreamFailures{0}; + }; + Stats mStats{}; +#endif +}; + +template +using bounded_vector = std::pmr::vector; + +template +inline void deepVectorClear(std::vector& vec) +{ + std::vector().swap(vec); +} + +template +inline void deepVectorClear(bounded_vector& vec, std::pmr::memory_resource* mr = nullptr) +{ + std::pmr::memory_resource* tmr = (mr != nullptr) ? mr : vec.get_allocator().resource(); + vec.~bounded_vector(); + new (&vec) bounded_vector(std::pmr::polymorphic_allocator{tmr}); +} + +template +inline void deepVectorClear(std::vector>& vec, std::pmr::memory_resource* mr = nullptr) +{ + for (auto& v : vec) { + deepVectorClear(v, mr); + } +} + +template +inline void deepVectorClear(std::array, S>& arr, std::pmr::memory_resource* mr = nullptr) +{ + for (size_t i{0}; i < S; ++i) { + deepVectorClear(arr[i], mr); + } +} + +template +inline void clearResizeBoundedVector(bounded_vector& vec, size_t sz, std::pmr::memory_resource* mr = nullptr, T def = T()) +{ + std::pmr::memory_resource* tmr = (mr != nullptr) ? mr : vec.get_allocator().resource(); + vec.~bounded_vector(); + new (&vec) bounded_vector(sz, def, std::pmr::polymorphic_allocator{tmr}); +} + +template +inline void clearResizeBoundedVector(std::vector>& vec, size_t size, std::pmr::memory_resource* mr) +{ + vec.clear(); + vec.reserve(size); + for (size_t i = 0; i < size; ++i) { + vec.emplace_back(std::pmr::polymorphic_allocator>{mr}); + } +} + +template +inline void clearResizeBoundedArray(std::array, S>& arr, size_t size, std::pmr::memory_resource* mr = nullptr, T def = T()) +{ + for (size_t i{0}; i < S; ++i) { + clearResizeBoundedVector(arr[i], size, mr, def); + } +} + +template +inline std::vector toSTDVector(const bounded_vector& b) +{ + std::vector t(b.size()); + std::copy(b.cbegin(), b.cend(), t.begin()); + return t; +} + +} // namespace o2::its + +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cell.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cell.h index 9ed5daed447df..4706977d08ba6 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cell.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cell.h @@ -15,109 +15,163 @@ #ifndef TRACKINGITSU_INCLUDE_CACELL_H_ #define TRACKINGITSU_INCLUDE_CACELL_H_ -#ifndef GPUCA_GPUCODE_DEVICE -#include -#include -#include -#endif +#include + +#include "ITStracking/Constants.h" +#include "ITStracking/LayerMask.h" +#include "DataFormatsITS/TimeEstBC.h" +#include "ReconstructionDataFormats/Track.h" #include "GPUCommonDef.h" -namespace o2 -{ -namespace its +namespace o2::its { -class Cell final +struct CellNeighbour { + int cellTopology{-1}; + int cell{-1}; + int nextCellTopology{-1}; + int nextCell{-1}; + int level{-1}; +}; + +template +class SeedBase : public o2::track::TrackParCovF { public: - GPUhd() Cell(); - GPUd() Cell(const int, const int, const int, const int, const int); - - GPUhd() int getFirstClusterIndex() const { return mFirstClusterIndex; }; - GPUhd() int getSecondClusterIndex() const { return mSecondClusterIndex; }; - GPUhd() int getThirdClusterIndex() const { return mThirdClusterIndex; }; - GPUhd() int getFirstTrackletIndex() const { return mFirstTrackletIndex; }; - GPUhd() int getSecondTrackletIndex() const { return mSecondTrackletIndex; }; + GPUhd() LayerMask getHitLayerMask() const { return LayerMask{static_cast(getUserField())}; } + GPUhd() void setHitLayerMask(LayerMask mask) { setUserField(mask.value()); } + GPUhd() int getInnerLayer() const { return getHitLayerMask().first(); } + GPUhd() int getFirstTrackletIndex() const { return mTracklets[0]; }; + GPUhd() void setFirstTrackletIndex(int trkl) { mTracklets[0] = trkl; }; + GPUhd() int getSecondTrackletIndex() const { return mTracklets[1]; }; + GPUhd() void setSecondTrackletIndex(int trkl) { mTracklets[1] = trkl; }; + GPUhd() float getChi2() const { return mChi2; }; + GPUhd() void setChi2(float chi2) { mChi2 = chi2; }; GPUhd() int getLevel() const { return mLevel; }; - GPUhd() void setLevel(const int level) { mLevel = level; }; + GPUhd() void setLevel(int level) { mLevel = level; }; GPUhd() int* getLevelPtr() { return &mLevel; } + GPUhd() auto& getTimeStamp() noexcept { return mTime; } + GPUhd() const auto& getTimeStamp() const noexcept { return mTime; } + + protected: + GPUhdDefault() SeedBase() = default; + GPUhdDefault() SeedBase(const SeedBase&) = default; + GPUhdDefault() ~SeedBase() = default; + GPUhdDefault() SeedBase(SeedBase&&) = default; + GPUhdDefault() SeedBase& operator=(const SeedBase&) = default; + GPUhdDefault() SeedBase& operator=(SeedBase&&) = default; + GPUhd() SeedBase(const o2::track::TrackParCovF& tpc, float chi2, int level, const TimeEstBC& time) + : o2::track::TrackParCovF(tpc), mChi2(chi2), mLevel(level), mTime(time) + { + } + GPUhd() auto& clustersRaw() { return mClusters; } + GPUhd() const auto& clustersRaw() const { return mClusters; } private: - const int mFirstClusterIndex; - const int mSecondClusterIndex; - const int mThirdClusterIndex; - const int mFirstTrackletIndex; - const int mSecondTrackletIndex; - int mLevel; + float mChi2{constants::UnsetValue}; + int mLevel{constants::UnusedIndex}; + std::array mTracklets = constants::helpers::initArray(); + std::array mClusters = constants::helpers::initArray(); + TimeEstBC mTime; }; -GPUhdi() Cell::Cell() - : mFirstClusterIndex{0}, - mSecondClusterIndex{0}, - mThirdClusterIndex{0}, - mFirstTrackletIndex{0}, - mSecondTrackletIndex{0}, - mLevel{0} +/// CellSeed: connections of three clusters +class CellSeed final : public SeedBase { - // Nothing to do -} - -GPUdi() Cell::Cell(const int firstClusterIndex, const int secondClusterIndex, const int thirdClusterIndex, - const int firstTrackletIndex, const int secondTrackletIndex) - : mFirstClusterIndex{firstClusterIndex}, - mSecondClusterIndex{secondClusterIndex}, - mThirdClusterIndex{thirdClusterIndex}, - mFirstTrackletIndex{firstTrackletIndex}, - mSecondTrackletIndex{secondTrackletIndex}, - mLevel{1} -{ - // Nothing to do -} + using Base = SeedBase; -class CellSeed final : public o2::track::TrackParCovF -{ public: GPUhdDefault() CellSeed() = default; + GPUhd() CellSeed(int innerL, int cl0, int cl1, int cl2, int trkl0, int trkl1, const o2::track::TrackParCovF& tpc, float chi2, const TimeEstBC& time) + : CellSeed(LayerMask(innerL, innerL + 1, innerL + 2), cl0, cl1, cl2, trkl0, trkl1, tpc, chi2, time) + { + } + GPUhd() CellSeed(LayerMask hitLayerMask, int cl0, int cl1, int cl2, int trkl0, int trkl1, const o2::track::TrackParCovF& tpc, float chi2, const TimeEstBC& time) + : Base(tpc, chi2, 1, time) + { + setHitLayerMask(hitLayerMask); + auto& clusters = this->clustersRaw(); + clusters[0] = cl0; + clusters[1] = cl1; + clusters[2] = cl2; + setFirstTrackletIndex(trkl0); + setSecondTrackletIndex(trkl1); + } GPUhdDefault() CellSeed(const CellSeed&) = default; GPUhdDefault() ~CellSeed() = default; - GPUd() CellSeed(int innerL, int cl0, int cl1, int cl2, int trkl0, int trkl1, o2::track::TrackParCovF& tpc, float chi2) : o2::track::TrackParCovF{tpc}, mLevel{1}, mChi2{chi2} + GPUhdDefault() CellSeed(CellSeed&&) = default; + GPUhdDefault() CellSeed& operator=(const CellSeed&) = default; + GPUhdDefault() CellSeed& operator=(CellSeed&&) = default; + + GPUhd() int getFirstClusterIndex() const { return this->clustersRaw()[0]; }; + GPUhd() int getSecondClusterIndex() const { return this->clustersRaw()[1]; }; + GPUhd() int getThirdClusterIndex() const { return this->clustersRaw()[2]; }; + GPUhd() auto& getClusters() { return this->clustersRaw(); } + GPUhd() const auto& getClusters() const { return this->clustersRaw(); } + /// getCluster takes an ABSOLUTE layer index. Compact cluster slots are + /// mapped to absolute layers by set-bit order in the hit-layer mask. + GPUhd() int getCluster(int layer) const { - setUserField(innerL); - mClusters[innerL + 0] = cl0; - mClusters[innerL + 1] = cl1; - mClusters[innerL + 2] = cl2; - mTracklets[0] = trkl0; - mTracklets[1] = trkl1; + const int slot = getHitLayerMask().slot(layer); + return (slot >= 0 && slot < constants::ClustersPerCell) ? this->clustersRaw()[slot] : constants::UnusedIndex; } - GPUhd() int getFirstClusterIndex() const { return mClusters[getUserField()]; }; - GPUhd() int getSecondClusterIndex() const { return mClusters[getUserField() + 1]; }; - GPUhd() int getThirdClusterIndex() const { return mClusters[getUserField() + 2]; }; - GPUhd() int getFirstTrackletIndex() const { return mTracklets[0]; }; - GPUhd() void setFirstTrackletIndex(int trkl) { mTracklets[0] = trkl; }; - GPUhd() int getSecondTrackletIndex() const { return mTracklets[1]; }; - GPUhd() void setSecondTrackletIndex(int trkl) { mTracklets[1] = trkl; }; - GPUhd() float getChi2() const { return mChi2; }; - GPUhd() void setChi2(float chi2) { mChi2 = chi2; }; - GPUhd() int getLevel() const { return mLevel; }; - GPUhd() void setLevel(int level) { mLevel = level; }; - GPUhd() int* getLevelPtr() { return &mLevel; } - GPUhd() int* getClusters() { return mClusters; } - GPUhd() int getCluster(int i) const { return mClusters[i]; } - GPUhdi() void printCell() const; +}; + +/// TrackSeed: full-width working representation used during road finding. +/// processNeighbours extends the cluster list inward, so we need NLayers +/// absolute-indexed slots here. +template +class TrackSeed final : public SeedBase +{ + using Base = SeedBase; + + public: + GPUhdDefault() TrackSeed() = default; + GPUhd() TrackSeed(const CellSeed& cs) + : Base(static_cast(cs), cs.getChi2(), cs.getLevel(), cs.getTimeStamp()) + { + this->setHitLayerMask(cs.getHitLayerMask()); + this->setFirstTrackletIndex(cs.getFirstTrackletIndex()); + this->setSecondTrackletIndex(cs.getSecondTrackletIndex()); + auto& clusters = this->clustersRaw(); + int slot = 0; + const auto hitMask = cs.getHitLayerMask(); + for (int layer = 0; layer < NLayers; ++layer) { + if (hitMask.has(layer)) { + clusters[layer] = cs.getClusters()[slot++]; + } + } + } + GPUhdDefault() TrackSeed(const TrackSeed&) = default; + GPUhdDefault() ~TrackSeed() = default; + GPUhdDefault() TrackSeed(TrackSeed&&) = default; + GPUhdDefault() TrackSeed& operator=(const TrackSeed&) = default; + GPUhdDefault() TrackSeed& operator=(TrackSeed&&) = default; + + GPUhd() int getFirstClusterIndex() const { return getClusterBySlot(0); } + GPUhd() int getSecondClusterIndex() const { return getClusterBySlot(1); } + GPUhd() int getThirdClusterIndex() const { return getClusterBySlot(2); } + GPUhd() auto& getClusters() { return this->clustersRaw(); } + GPUhd() const auto& getClusters() const { return this->clustersRaw(); } + GPUhd() int getCluster(int layer) const { return this->clustersRaw()[layer]; } private: - int mClusters[7] = {-1, -1, -1, -1, -1, -1, -1}; - int mTracklets[2] = {-1, -1}; - int mLevel = 0; - float mChi2 = 0.f; + GPUhd() int getClusterBySlot(int requestedSlot) const + { + int slot = 0; + const auto hitMask = this->getHitLayerMask(); + for (int layer = 0; layer < NLayers; ++layer) { + if (hitMask.has(layer)) { + if (slot++ == requestedSlot) { + return this->clustersRaw()[layer]; + } + } + } + return constants::UnusedIndex; + } }; -GPUhdi() void CellSeed::printCell() const -{ - printf("trkl: %d, %d\t lvl: %d\t chi2: %f\n", mTracklets[0], mTracklets[1], mLevel, mChi2); -} +} // namespace o2::its -} // 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 0f136edfebfb3..34014d858648b 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cluster.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cluster.h @@ -16,73 +16,68 @@ #ifndef TRACKINGITSU_INCLUDE_CACLUSTER_H_ #define TRACKINGITSU_INCLUDE_CACLUSTER_H_ -#ifndef GPUCA_GPUCODE_DEVICE #include -#endif - +#include "ITStracking/Constants.h" #include "GPUCommonRtypes.h" -#include "GPUCommonArray.h" -#include "ITStracking/Definitions.h" -#include "ITStracking/MathUtils.h" +#include "GPUCommonDef.h" -namespace o2 -{ -namespace its +namespace o2::its { +template class IndexTableUtils; struct Cluster final { - Cluster() = default; - Cluster(const float x, const float y, const float z, const int idx); - 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&); - bool operator==(const Cluster&) const; + GPUhdDefault() Cluster() = default; + GPUhd() Cluster(const float x, const float y, const float z, const int idx); + template + GPUhd() Cluster(const int, const IndexTableUtils& utils, const Cluster&); + template + GPUhd() Cluster(const int, const float3&, const IndexTableUtils& utils, const Cluster&); + GPUhdDefault() Cluster(const Cluster&) = default; + GPUhdDefault() Cluster(Cluster&&) noexcept = default; + GPUhdDefault() ~Cluster() = default; + + GPUhdDefault() Cluster& operator=(const Cluster&) = default; + GPUhdDefault() Cluster& operator=(Cluster&&) noexcept = default; + GPUhdDefault() bool operator==(const Cluster&) const = default; + GPUhd() void print() const; - float xCoordinate; // = -999.f; - float yCoordinate; // = -999.f; - float zCoordinate; // = -999.f; - float phi; // = -999.f; - float radius; // = -999.f; - int clusterId; // = -1; - int indexTableBinIndex; // = -1; + float xCoordinate{-999.f}; + float yCoordinate{-999.f}; + float zCoordinate{-999.f}; + float phi{-999.f}; + float radius{-999.f}; + int clusterId{constants::UnusedIndex}; + int indexTableBinIndex{constants::UnusedIndex}; ClassDefNV(Cluster, 1); }; -GPUhdi() void Cluster::print() const -{ -#if !defined(GPUCA_GPUCODE_DEVICE) || (!defined(__OPENCL__) && defined(GPUCA_GPU_DEBUG_PRINT)) - printf("Cluster: %f %f %f %f %f %d %d\n", xCoordinate, yCoordinate, zCoordinate, phi, radius, clusterId, indexTableBinIndex); -#endif -} - -struct TrackingFrameInfo { - TrackingFrameInfo() = default; - TrackingFrameInfo(float x, float y, float z, float xTF, float alpha, o2::gpu::gpustd::array&& posTF, o2::gpu::gpustd::array&& covTF); - - float xCoordinate; - float yCoordinate; - float zCoordinate; - float xTrackingFrame; - float alphaTrackingFrame; - o2::gpu::gpustd::array positionTrackingFrame = {-1., -1.}; - o2::gpu::gpustd::array covarianceTrackingFrame = {999., 999., 999.}; - GPUdi() void print() const - { -#if !defined(GPUCA_GPUCODE_DEVICE) || (!defined(__OPENCL__) && defined(GPUCA_GPU_DEBUG_PRINT)) - printf("x: %f y: %f z: %f xTF: %f alphaTF: %f posTF: %f %f covTF: %f %f %f\n", - xCoordinate, yCoordinate, zCoordinate, xTrackingFrame, alphaTrackingFrame, - positionTrackingFrame[0], positionTrackingFrame[1], - covarianceTrackingFrame[0], covarianceTrackingFrame[1], covarianceTrackingFrame[2]); -#endif - } +struct TrackingFrameInfo final { + GPUhdDefault() TrackingFrameInfo() = default; + GPUhd() TrackingFrameInfo(float x, float y, float z, float xTF, float alpha, std::array&& posTF, std::array&& covTF); + GPUhdDefault() TrackingFrameInfo(const TrackingFrameInfo&) = default; + GPUhdDefault() TrackingFrameInfo(TrackingFrameInfo&&) noexcept = default; + GPUhdDefault() ~TrackingFrameInfo() = default; + + GPUhdDefault() TrackingFrameInfo& operator=(const TrackingFrameInfo&) = default; + GPUhdDefault() TrackingFrameInfo& operator=(TrackingFrameInfo&&) = default; + + GPUhd() void print() const; + + float xCoordinate{-999.f}; + float yCoordinate{-999.f}; + float zCoordinate{-999.f}; + float xTrackingFrame{-999.f}; + float alphaTrackingFrame{-999.f}; + std::array positionTrackingFrame = {-999.f, -999.f}; + std::array covarianceTrackingFrame = {-999.f, -999.f, -999.f}; ClassDefNV(TrackingFrameInfo, 1); }; -} // namespace its -} // namespace o2 + +} // namespace o2::its #endif /* TRACKINGITSU_INCLUDE_CACLUSTER_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ClusterLines.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ClusterLines.h index 3377b88e89069..bcb8a98a62cab 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ClusterLines.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ClusterLines.h @@ -12,238 +12,81 @@ #ifndef O2_ITS_CLUSTERLINES_H #define O2_ITS_CLUSTERLINES_H -#include +#include #include +#include +#include +#include #include "ITStracking/Cluster.h" -#include "ITStracking/Definitions.h" +#include "ITStracking/Constants.h" #include "ITStracking/Tracklet.h" -#include "GPUCommonMath.h" +#include "GPUCommonRtypes.h" namespace o2::its { -struct Line final { - GPUhd() Line(); - GPUhd() Line(const Line&); - Line(std::array firstPoint, std::array secondPoint); - GPUhd() Line(const float firstPoint[3], const float secondPoint[3]); - GPUhd() Line(const Tracklet&, const Cluster*, const Cluster*); - - static float getDistanceFromPoint(const Line& line, const std::array& point); - GPUhd() static float getDistanceFromPoint(const Line& line, const float point[3]); - static std::array getDCAComponents(const Line& line, const std::array point); - GPUhd() static void getDCAComponents(const Line& line, const float point[3], float destArray[6]); - GPUhd() static float getDCA(const Line&, const Line&, const float precision = 1e-14); - static bool areParallel(const Line&, const Line&, const float precision = 1e-14); - GPUhd() unsigned char isEmpty() const { return (originPoint[0] == 0.f && originPoint[1] == 0.f && originPoint[2] == 0.f) && - (cosinesDirector[0] == 0.f && cosinesDirector[1] == 0.f && cosinesDirector[2] == 0.f); } - GPUhdi() auto getDeltaROF() const { return rof[1] - rof[0]; } - GPUhd() void print() const; - bool operator==(const Line&) const; - bool operator!=(const Line&) const; - short getMinROF() const { return rof[0] < rof[1] ? rof[0] : rof[1]; } - - float originPoint[3], cosinesDirector[3]; - float weightMatrix[6] = {1., 0., 0., 1., 0., 1.}; - // weightMatrix is a symmetric matrix internally stored as - // 0 --> row = 0, col = 0 - // 1 --> 0,1 - // 2 --> 0,2 - // 3 --> 1,1 - // 4 --> 1,2 - // 5 --> 2,2 - short rof[2]; -}; - -GPUhdi() Line::Line() : weightMatrix{1., 0., 0., 1., 0., 1.} -{ - rof[0] = -1; - rof[1] = -1; -} - -GPUhdi() Line::Line(const Line& other) -{ - for (int i{0}; i < 3; ++i) { - originPoint[i] = other.originPoint[i]; - cosinesDirector[i] = other.cosinesDirector[i]; - } - for (int i{0}; i < 6; ++i) { - weightMatrix[i] = other.weightMatrix[i]; - } - for (int i{0}; i < 2; ++i) { - rof[i] = other.rof[i]; - } -} - -GPUhdi() Line::Line(const float firstPoint[3], const float secondPoint[3]) -{ - for (int i{0}; i < 3; ++i) { - originPoint[i] = firstPoint[i]; - cosinesDirector[i] = secondPoint[i] - firstPoint[i]; - } - - 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; - } - - rof[0] = -1; - rof[1] = -1; -} - -GPUhdi() Line::Line(const Tracklet& tracklet, const Cluster* innerClusters, const Cluster* outerClusters) -{ - originPoint[0] = innerClusters[tracklet.firstClusterIndex].xCoordinate; - originPoint[1] = innerClusters[tracklet.firstClusterIndex].yCoordinate; - originPoint[2] = innerClusters[tracklet.firstClusterIndex].zCoordinate; - - cosinesDirector[0] = outerClusters[tracklet.secondClusterIndex].xCoordinate - innerClusters[tracklet.firstClusterIndex].xCoordinate; - cosinesDirector[1] = outerClusters[tracklet.secondClusterIndex].yCoordinate - innerClusters[tracklet.firstClusterIndex].yCoordinate; - cosinesDirector[2] = outerClusters[tracklet.secondClusterIndex].zCoordinate - innerClusters[tracklet.firstClusterIndex].zCoordinate; - - 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; - } - - rof[0] = tracklet.rof[0]; - rof[1] = tracklet.rof[1]; -} +struct Line final { +#if !defined(__HIPCC__) && !defined(__CUDACC__) // hide the class completely for gpu-cc + using SVector3f = ROOT::Math::SVector; + using SMatrix3f = ROOT::Math::SMatrix>; -// static functions: -inline float Line::getDistanceFromPoint(const Line& line, const std::array& point) -{ - float DCASquared{0}; - float cdelta{0}; - for (int i{0}; i < 3; ++i) { - cdelta -= line.cosinesDirector[i] * (line.originPoint[i] - point[i]); - } - for (int i{0}; i < 3; ++i) { - DCASquared += (line.originPoint[i] - point[i] + line.cosinesDirector[i] * cdelta) * - (line.originPoint[i] - point[i] + line.cosinesDirector[i] * cdelta); - } - return o2::gpu::CAMath::Sqrt(DCASquared); -} + Line() = default; + Line(const Tracklet&, const Cluster*, const Cluster*); + bool operator==(const Line&) const = default; -GPUhdi() float Line::getDistanceFromPoint(const Line& line, const float point[3]) -{ - float DCASquared{0}; - float cdelta{0}; - for (int i{0}; i < 3; ++i) { - cdelta -= line.cosinesDirector[i] * (line.originPoint[i] - point[i]); - } - for (int i{0}; i < 3; ++i) { - DCASquared += (line.originPoint[i] - point[i] + line.cosinesDirector[i] * cdelta) * - (line.originPoint[i] - point[i] + line.cosinesDirector[i] * cdelta); - } - return o2::gpu::CAMath::Sqrt(DCASquared); -} + static float getDistance2FromPoint(const Line& line, const std::array& point); + static float getDistanceFromPoint(const Line& line, const std::array& point); + static SMatrix3f getDCAComponents(const Line& line, const std::array& point); + static float getDCA2(const Line&, const Line&, const float precision = constants::Tolerance); + static float getDCA(const Line&, const Line&, const float precision = constants::Tolerance); + bool isEmpty() const noexcept; + void print() const; -GPUhdi() float Line::getDCA(const Line& firstLine, const Line& secondLine, const float precision) -{ - float normalVector[3]; - normalVector[0] = firstLine.cosinesDirector[1] * secondLine.cosinesDirector[2] - - firstLine.cosinesDirector[2] * secondLine.cosinesDirector[1]; - normalVector[1] = -firstLine.cosinesDirector[0] * secondLine.cosinesDirector[2] + - firstLine.cosinesDirector[2] * secondLine.cosinesDirector[0]; - normalVector[2] = firstLine.cosinesDirector[0] * secondLine.cosinesDirector[1] - - firstLine.cosinesDirector[1] * secondLine.cosinesDirector[0]; + SVector3f originPoint; + SVector3f cosinesDirector; + TimeEstBC mTime; - float norm{0.f}, distance{0.f}; - for (int i{0}; i < 3; ++i) { - norm += normalVector[i] * normalVector[i]; - distance += (secondLine.originPoint[i] - firstLine.originPoint[i]) * normalVector[i]; - } - if (norm > precision) { - return o2::gpu::CAMath::Abs(distance / o2::gpu::CAMath::Sqrt(norm)); - } else { -#if defined(__CUDACC__) || defined(__HIPCC__) - float stdOriginPoint[3]; - for (int i{0}; i < 3; ++i) { - stdOriginPoint[i] = secondLine.originPoint[1]; - } -#else - std::array stdOriginPoint = {}; - std::copy_n(secondLine.originPoint, 3, stdOriginPoint.begin()); + ClassDefNV(Line, 1); #endif - return getDistanceFromPoint(firstLine, stdOriginPoint); - } -} - -GPUhdi() void Line::getDCAComponents(const Line& line, const float point[3], float destArray[6]) -{ - float cdelta{0.}; - for (int i{0}; i < 3; ++i) { - cdelta -= line.cosinesDirector[i] * (line.originPoint[i] - point[i]); - } - - destArray[0] = line.originPoint[0] - point[0] + line.cosinesDirector[0] * cdelta; - destArray[3] = line.originPoint[1] - point[1] + line.cosinesDirector[1] * cdelta; - destArray[5] = line.originPoint[2] - point[2] + line.cosinesDirector[2] * cdelta; - destArray[1] = o2::gpu::CAMath::Sqrt(destArray[0] * destArray[0] + destArray[3] * destArray[3]); - destArray[2] = o2::gpu::CAMath::Sqrt(destArray[0] * destArray[0] + destArray[5] * destArray[5]); - destArray[4] = o2::gpu::CAMath::Sqrt(destArray[3] * destArray[3] + destArray[5] * destArray[5]); -} - -inline bool Line::operator==(const Line& rhs) const -{ - bool val{false}; - for (int i{0}; i < 3; ++i) { - val &= this->originPoint[i] == rhs.originPoint[i]; - } - return val; -} - -inline bool Line::operator!=(const Line& rhs) const -{ - bool val; - for (int i{0}; i < 3; ++i) { - val &= this->originPoint[i] != rhs.originPoint[i]; - } - return val; -} - -GPUhdi() void Line::print() const -{ - printf("Line: originPoint = (%f, %f, %f), cosinesDirector = (%f, %f, %f), rofs = (%hd, %hd)\n", - originPoint[0], originPoint[1], originPoint[2], cosinesDirector[0], cosinesDirector[1], cosinesDirector[2], rof[0], rof[1]); -} +}; class ClusterLines final { +#if !defined(__HIPCC__) && !defined(__CUDACC__) // hide the class completely for gpu-cc + using SMatrix3 = ROOT::Math::SMatrix>; + using SMatrix3f = ROOT::Math::SMatrix>; + using SVector3 = ROOT::Math::SVector; + public: ClusterLines() = default; - ClusterLines(const int firstLabel, const Line& firstLine, const int secondLabel, const Line& secondLine, - const bool weight = false); - ClusterLines(const Line& firstLine, const Line& secondLine); - void add(const int& lineLabel, const Line& line, const bool& weight = false); + ClusterLines(const int firstLabel, const Line& firstLine, const int secondLabel, const Line& secondLine); + ClusterLines(gsl::span lineLabels, gsl::span lines); + void add(const int lineLabel, const Line& line); void computeClusterCentroid(); - void updateROFPoll(const Line&); - inline std::vector& getLabels() - { - return mLabels; - } - inline int getSize() const { return mLabels.size(); } - inline short getROF() const { return mROF; } - inline std::array getVertex() const { return mVertex; } - inline std::array getRMS2() const { return mRMS2; } - inline float getAvgDistance2() const { return mAvgDistance2; } - - bool operator==(const ClusterLines&) const; + void accumulate(const Line& line); + bool isValid() const noexcept { return mIsValid; } + auto const& getVertex() const { return mVertex; } + const float* getRMS2() const { return mRMS2.Array(); } + float getAvgDistance2() const { return mAvgDistance2; } + auto getSize() const noexcept { return mLabels.size(); } + auto& getLabels() const noexcept { return mLabels; } + const auto& getTimeStamp() const noexcept { return mTime; } + bool operator==(const ClusterLines& rhs) const noexcept; + float getR2() const noexcept { return (mVertex[0] * mVertex[0]) + (mVertex[1] * mVertex[1]); } + float getR() const noexcept { return std::sqrt(getR2()); } protected: - std::array mAMatrix; // AX=B - std::array mBMatrix; // AX=B - std::vector mLabels; // labels - std::array mWeightMatrix = {0.f}; // weight matrix - std::array mVertex = {0.f}; // cluster centroid position - std::array mRMS2 = {0.f}; // symmetric matrix: diagonal is RMS2 - float mAvgDistance2 = 0.f; // substitute for chi2 - int mROFWeight = 0; // rof weight for voting - short mROF = -1; // rof + SMatrix3 mAMatrix; // AX=B, symmetric normal matrix + SVector3 mBMatrix; // AX=B, right-hand side + std::array mVertex = {}; // cluster centroid position + SMatrix3f mRMS2; // symmetric matrix: diagonal is RMS2 + float mAvgDistance2 = 0.f; // substitute for chi2 + bool mIsValid = false; // true if linear system was solved successfully + TimeEstBC mTime; // time stamp + std::vector mLabels; // contributing labels + + ClassDefNV(ClusterLines, 1); +#endif }; } // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h index b63a01cb8cd29..275752854665b 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h @@ -16,57 +16,48 @@ #ifndef TRACKINGITSU_INCLUDE_CONFIGURATION_H_ #define TRACKINGITSU_INCLUDE_CONFIGURATION_H_ +#include #ifndef GPUCA_GPUCODE_DEVICE -#include -#include +#include +#include #include -#include #endif +#include "CommonUtils/EnumFlags.h" #include "DetectorsBase/Propagator.h" #include "ITStracking/Constants.h" +#include "ITStracking/LayerMask.h" -namespace o2 -{ -namespace its +namespace o2::its { -enum class TrackingMode { - Sync, - Async, - Cosmics, - Unset, // Special value to leave a default in case we want to override via Configurable Params +// Steering of dedicated steps in an iteration +enum class IterationStep : uint8_t { + FirstPass = 0, + RebuildClusterLUT, + UseUPCMask, + SelectUPCVertices, + ResetVertices, + SkipROFsAboveThreshold, + MarkVerticesAsUPC, }; +using IterationSteps = o2::utils::EnumFlags; -std::string asString(TrackingMode mode); -std::ostream& operator<<(std::ostream& os, TrackingMode v); - -template -class Configuration : public Param -{ - public: - static Configuration& getInstance() +struct TrackingParameters { + int CellMinimumLevel() const noexcept { - static Configuration instance; - return instance; + const int minClusters = MinTrackLength - (MaxHoles > 0 ? MaxHoles : 0); + const int effectiveMinClusters = minClusters > constants::ClustersPerCell ? minClusters : constants::ClustersPerCell; + return effectiveMinClusters - constants::ClustersPerCell + 1; } - Configuration(const Configuration&) = delete; - const Configuration& operator=(const Configuration&) = delete; - - private: - Configuration() = default; -}; - -struct TrackingParameters { - TrackingParameters& operator=(const TrackingParameters& t) = default; - - int CellMinimumLevel(); - int CellsPerRoad() const { return NLayers - 2; } - int TrackletsPerRoad() const { return NLayers - 1; } + int NeighboursPerRoad() const noexcept { return NLayers - 3; } + int CellsPerRoad() const noexcept { return NLayers - 2; } + int TrackletsPerRoad() const noexcept { return NLayers - 1; } std::string asString() const; + IterationSteps PassFlags{IterationStep::FirstPass, IterationStep::RebuildClusterLUT}; int NLayers = 7; - int DeltaROF = 0; + std::vector AddTimeError = {0, 0, 0, 0, 0, 0, 0}; std::vector LayerZ = {16.333f + 1, 16.333f + 1, 16.333f + 1, 42.140f + 1, 42.140f + 1, 73.745f + 1, 73.745f + 1}; std::vector LayerRadii = {2.33959f, 3.14076f, 3.91924f, 19.6213f, 24.5597f, 34.388f, 39.3329f}; std::vector LayerxX0 = {5.e-3f, 5.e-3f, 5.e-3f, 1.e-2f, 1.e-2f, 1.e-2f, 1.e-2f}; @@ -75,97 +66,103 @@ struct TrackingParameters { std::vector SystErrorZ2 = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; int ZBins{256}; int PhiBins{128}; - int nROFsPerIterations = -1; bool UseDiamond = false; float Diamond[3] = {0.f, 0.f, 0.f}; + float DiamondCov[6] = {25.e-6f, 0.f, 0.f, 25.e-6f, 0.f, 36.f}; /// General parameters - int ClusterSharing = 0; int MinTrackLength = 7; + int MaxHoles = 0; + LayerMask HoleLayerMask = 0; float NSigmaCut = 5; float PVres = 1.e-2f; /// Trackleting cuts float TrackletMinPt = 0.3f; - float TrackletsPerClusterLimit = 2.f; /// Cell finding cuts float CellDeltaTanLambdaSigma = 0.007f; - float CellsPerClusterLimit = 2.f; /// Fitter parameters o2::base::PropagatorImpl::MatCorrType CorrType = o2::base::PropagatorImpl::MatCorrType::USEMatCorrNONE; - unsigned long MaxMemory = 12000000000UL; float MaxChi2ClusterAttachment = 60.f; float MaxChi2NDF = 30.f; + int ReseedIfShorter = 6; // reseed for the final fit track with the length shorter than this std::vector MinPt = {0.f, 0.f, 0.f, 0.f}; - unsigned char StartLayerMask = 0x7F; - bool FindShortTracks = false; + LayerMask StartLayerMask = 0x7F; + bool RepeatRefitOut = false; // repeat outward refit using inward refit as a seed + bool ShiftRefToCluster = true; // TrackFit: after update shift the linearization reference to cluster bool PerPrimaryVertexProcessing = false; bool SaveTimeBenchmarks = false; bool DoUPCIteration = false; bool FataliseUponFailure = true; + bool CreateArtefactLabels{false}; + bool PrintMemory = false; // print allocator usage in epilog report + size_t MaxMemory = std::numeric_limits::max(); bool DropTFUponFailure = false; - /// Cluster attachment - bool UseTrackFollower = false; - bool UseTrackFollowerTop = false; - bool UseTrackFollowerBot = false; - bool UseTrackFollowerMix = false; - float TrackFollowerNSigmaCutZ = 1.f; - float TrackFollowerNSigmaCutPhi = 1.f; -}; -inline int TrackingParameters::CellMinimumLevel() -{ - return MinTrackLength - constants::its::ClustersPerCell + 1; -} + // Selections on tracks sharing clusters + bool AllowSharingFirstCluster = false; + float SharedClusterMaxDeltaPhi = 0.05f; // For tracks sharing clusters, maximum allowed delta phi at the cluster position + float SharedClusterMaxDeltaEta = 0.03f; // For tracks sharing clusters, maximum allowed delta eta at the cluster position + bool SharedClusterOppositeSign = false; // For tracks sharing clusters, require opposite sign of the tracklets + int SharedMaxClusters = 0; // Maximal allowed shared clusters (excluding first cluster) +}; struct VertexingParameters { - int nIterations = 1; // Number of vertexing passes to perform - int vertPerRofThreshold = 0; // Maximum number of vertices per ROF to trigger second a round - bool allowSingleContribClusters = false; + std::string asString() const; + + IterationSteps PassFlags{IterationStep::FirstPass, IterationStep::ResetVertices}; std::vector LayerZ = {16.333f + 1, 16.333f + 1, 16.333f + 1, 42.140f + 1, 42.140f + 1, 73.745f + 1, 73.745f + 1}; std::vector LayerRadii = {2.33959f, 3.14076f, 3.91924f, 19.6213f, 24.5597f, 34.388f, 39.3329f}; - int ZBins{1}; - int PhiBins{128}; - int deltaRof = 0; - float zCut = 0.002f; - float phiCut = 0.005f; - float pairCut = 0.04f; - float clusterCut = 0.8f; - float histPairCut = 0.04f; - float tanLambdaCut = 0.002f; // tanLambda = deltaZ/deltaR - float lowMultBeamDistCut = 0.1f; // XY cut for low-multiplicity pile up - int vertNsigmaCut = 6; // N sigma cut for vertex XY - float vertRadiusSigma = 0.33f; // sigma of vertex XY - float trackletSigma = 0.01f; // tracklet to vertex sigma - float maxZPositionAllowed = 25.f; - int clusterContributorsCut = 16; - int maxTrackletsPerCluster = 2e3; + int vertPerRofThreshold = 0; // Maximum number of vertices per ROF to trigger second a round + int ZBins = 1; + int PhiBins = 128; + float zCut = -1.f; + float phiCut = -1.f; + float pairCut = -1.f; + float clusterCut = -1.f; + float coarseZWindow = -1.f; + float seedDedupZCut = -1.f; + float refitDedupZCut = -1.f; + float duplicateZCut = -1.f; + float finalSelectionZCut = -1.f; + float duplicateDistance2Cut = -1.f; + float tanLambdaCut = -1.f; + float NSigmaCut = -1; + float maxZPositionAllowed = -1.f; + int clusterContributorsCut = -1; + int suppressLowMultDebris = -1; + int seedMemberRadiusTime = -1; + int seedMemberRadiusZ = -1; + int maxTrackletsPerCluster = -1; int phiSpan = -1; int zSpan = -1; + bool SaveTimeBenchmarks = false; + + bool useTruthSeeding = false; // overwrite found vertices with MC events int nThreads = 1; + bool PrintMemory = false; // print allocator usage in epilog report + size_t MaxMemory = std::numeric_limits::max(); + bool DropTFUponFailure = false; }; -struct TimeFrameGPUParameters { - TimeFrameGPUParameters() = default; - - size_t tmpCUBBufferSize = 1e5; // In average in pp events there are required 4096 bytes - size_t maxTrackletsPerCluster = 1e2; - size_t clustersPerLayerCapacity = 2.5e5; - size_t clustersPerROfCapacity = 1.5e3; - size_t validatedTrackletsCapacity = 1e3; - size_t cellsLUTsize = validatedTrackletsCapacity; - size_t maxNeighboursSize = 1e2; - size_t neighboursLUTsize = maxNeighboursSize; - size_t maxRoadPerRofSize = 1e3; // pp! - size_t maxLinesCapacity = 1e2; - size_t maxVerticesCapacity = 5e4; - size_t nMaxROFs = 1e3; - size_t nTimeFrameChunks = 3; - size_t nROFsPerChunk = 768; // pp defaults - int maxGPUMemoryGB = -1; +namespace TrackingMode +{ +enum Type : int8_t { + Unset = -1, // Special value to leave a default in case we want to override via Configurable Params + Sync = 0, + Async = 1, + Cosmics = 2, + Off = 3, }; -} // namespace its -} // namespace o2 +Type fromString(std::string_view str); +std::string toString(Type mode); + +std::vector getTrackingParameters(Type mode); +std::vector getVertexingParameters(Type mode); + +}; // namespace TrackingMode + +} // namespace o2::its #endif /* TRACKINGITSU_INCLUDE_CONFIGURATION_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Constants.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Constants.h index da02149fbc432..34fa819b178eb 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Constants.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Constants.h @@ -16,113 +16,37 @@ #ifndef TRACKINGITSU_INCLUDE_CONSTANTS_H_ #define TRACKINGITSU_INCLUDE_CONSTANTS_H_ -#ifndef GPUCA_GPUCODE_DEVICE -#include -#include -#endif +#include +#include -#include "ITStracking/Definitions.h" -#include "CommonConstants/MathConstants.h" - -#include "GPUCommonMath.h" -#include "GPUCommonDef.h" -#include "GPUCommonArray.h" - -namespace o2 -{ -namespace its +namespace o2::its::constants { -namespace constants -{ -constexpr float MB = 1024.f * 1024.f; -constexpr float GB = 1024.f * 1024.f * 1024.f; +constexpr float KB = 1024.f; +constexpr float MB = KB * KB; +constexpr float GB = MB * KB; constexpr bool DoTimeBenchmarks = true; constexpr bool SaveTimeBenchmarks = false; +constexpr float Tolerance = 1e-12; // numerical tolerance +constexpr int ClustersPerCell = 3; // number of clusters for a cell +constexpr int UnusedIndex = -1; // global unused flag +constexpr float UnsetValue = -999.f; // global unset value +constexpr float Radl = 9.36f; // Radiation length of Si [cm] +constexpr float Rho = 2.33f; // Density of Si [g/cm^3] +constexpr int MaxIter = 4; // Max. supported iterations +constexpr int MaxSelectedTrackletsPerCluster = 100; // vertexer: max lines per cluster -namespace math +namespace helpers { -constexpr float Pi{3.14159265359f}; -constexpr float TwoPi{2.0f * Pi}; -constexpr float FloatMinThreshold{1e-20f}; -} // namespace math - -namespace its -{ -constexpr int LayersNumberVertexer{3}; -constexpr int ClustersPerCell{3}; -constexpr int UnusedIndex{-1}; -constexpr float Resolution{0.0005f}; - -GPUhdi() constexpr o2::gpu::gpustd::array VertexerHistogramVolume() -{ - return o2::gpu::gpustd::array{{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 o2::gpu::gpustd::array LayersZCoordinate() -{ - constexpr double s = 1.; // safety margin - return o2::gpu::gpustd::array{16.333f + s, 16.333f + s, 16.333f + s, 42.140f + s, 42.140f + s, 73.745f + s, 73.745f + s}; -} - -GPUhdi() constexpr o2::gpu::gpustd::array LayersRCoordinate() -{ - return o2::gpu::gpustd::array{{2.33959f, 3.14076f, 3.91924f, 19.6213f, 24.5597f, 34.388f, 39.3329f}}; -} -constexpr int ZBins{256}; -constexpr int PhiBins{128}; -constexpr float InversePhiBinSize{PhiBins / constants::math::TwoPi}; -GPUhdi() constexpr o2::gpu::gpustd::array InverseZBinSize() +// initialize a std::array at compile time fully with T +template +constexpr std::array initArray() { - constexpr auto zSize = LayersZCoordinate(); - return o2::gpu::gpustd::array{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 [](std::index_sequence) { return std::array{(static_cast(Is), Value)...}; }(std::make_index_sequence{}); } -GPUhdi() constexpr float getInverseZCoordinate(const int layerIndex) -{ - return 0.5f * ZBins / LayersZCoordinate()[layerIndex]; -} - -GPUhdi() int getZBinIndex(const int layerIndex, const float zCoordinate) -{ - return (zCoordinate + LayersZCoordinate()[layerIndex]) * - InverseZBinSize()[layerIndex]; -} - -GPUhdi() int getPhiBinIndex(const float currentPhi) -{ - return (currentPhi * InversePhiBinSize); -} - -GPUhdi() int getBinIndex(const int zIndex, const int phiIndex) -{ - return o2::gpu::GPUCommonMath::Min(phiIndex * ZBins + zIndex, - ZBins * PhiBins - 1); -} - -GPUhdi() constexpr int4 getEmptyBinsRect() { return int4{0, 0, 0, 0}; } - -} // namespace its2 - -namespace pdgcodes -{ -constexpr int PionCode{211}; -} -} // namespace constants -#ifndef GPUCA_GPUCODE_DEVICE -typedef std::vector> index_table_t; -#endif -} // namespace its -} // namespace o2 +} // namespace helpers +} // namespace o2::its::constants #endif /* TRACKINGITSU_INCLUDE_CONSTANTS_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Definitions.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Definitions.h index 352e13963b6d1..d79ea8c8bece8 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Definitions.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Definitions.h @@ -1,4 +1,4 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. // See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. // All rights not expressly granted are reserved. // @@ -15,15 +15,54 @@ #ifndef TRACKINGITS_DEFINITIONS_H_ #define TRACKINGITS_DEFINITIONS_H_ -#ifndef GPUCA_GPUCODE_DEVICE -#include -#endif +#include +#include + +namespace o2::its +{ + +enum class TrackletMode { + Layer0Layer1 = 0, + Layer1Layer2 = 2 +}; + +template +using maybe_const = typename std::conditional::type; + +// simple implemnetion of logging with exp. backoff +struct LogLogThrottler { + uint64_t evCount{0}; + uint64_t nextLog{1}; + int32_t iteration{-1}; + int32_t layer{-1}; + bool needToLog(int32_t iter, int32_t lay) + { + if (iteration != iter || layer != lay) { + iteration = iter; + layer = lay; + evCount = 0; + nextLog = 1; + } + if (++evCount > nextLog) { + nextLog *= 2; + return true; + } + return false; + } +}; + +struct TimingStats { + std::uint64_t calls = 0; + double totalTimeMs = 0.; + + void add(double timeMs) + { + ++calls; + totalTimeMs += timeMs; + } + double averageTimeMs() const { return calls ? totalTimeMs / static_cast(calls) : 0.; } +}; + +} // namespace o2::its -#ifdef CA_DEBUG -#define CA_DEBUGGER(x) x -#else -#define CA_DEBUGGER(x) \ - do { \ - } while (0) -#endif #endif diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ExternalAllocator.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ExternalAllocator.h index 9bdb2905ba9ba..7d1e98736db2c 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ExternalAllocator.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ExternalAllocator.h @@ -16,13 +16,69 @@ #ifndef TRACKINGITSU_INCLUDE_EXTERNALALLOCATOR_H_ #define TRACKINGITSU_INCLUDE_EXTERNALALLOCATOR_H_ +#include +#include "GPUO2ExternalUser.h" +#include "Base/GPUMemoryResource.h" + namespace o2::its { class ExternalAllocator { + using Type = std::underlying_type_t; + public: + virtual void deallocate(char*, size_t) = 0; virtual void* allocate(size_t) = 0; + void* allocate(size_t s, Type type) + { + auto old = mType; + mType = type; + void* p = allocate(s); + mType = old; + return p; + } + void* allocateStack(size_t s) + { + return allocate(s, (o2::gpu::GPUMemoryResource::MEMORY_GPU | o2::gpu::GPUMemoryResource::MEMORY_STACK)); + } + virtual void pushTagOnStack(uint64_t) = 0; + virtual void popTagOffStack(uint64_t) = 0; + + void setType(Type t) noexcept { mType = t; } + Type getType() const noexcept { return mType; } + + protected: + Type mType; +}; + +class ExternalAllocatorAdaptor final : public std::pmr::memory_resource +{ + public: + explicit ExternalAllocatorAdaptor(ExternalAllocator* alloc) : mAlloc(alloc) {} + + protected: + void* do_allocate(size_t bytes, size_t alignment) override + { + void* p = mAlloc->allocate(bytes, o2::gpu::GPUMemoryResource::MemoryType::MEMORY_HOST); + if (!p) { + throw std::bad_alloc(); + } + return p; + } + + void do_deallocate(void* p, size_t bytes, size_t) override + { + mAlloc->deallocate(static_cast(p), bytes); + } + + bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override + { + return this == &other; + } + + private: + ExternalAllocator* mAlloc; }; } // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/FastMultEst.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/FastMultEst.h new file mode 100644 index 0000000000000..f94c7c2034b46 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/FastMultEst.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 FastMultEst.h +/// \brief Fast multiplicity estimator for ITS +/// \author ruben.shahoyan@cern.ch + +#ifndef ALICEO2_ITS_FASTMULTEST_ +#define ALICEO2_ITS_FASTMULTEST_ + +#include "ITSMFTReconstruction/ChipMappingITS.h" +#include "DataFormatsITS/Vertex.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/PhysTrigger.h" +#include "ITStracking/FastMultEstConfig.h" +#include "ITStracking/ROFLookupTables.h" +#include +#include + +namespace o2::its +{ + +struct FastMultEst { + + static constexpr int NLayers = o2::itsmft::ChipMappingITS::NLayers; + using ROFOverlapTableN = ROFOverlapTable; + using ROFMaskTableN = ROFMaskTable; + + float mult = 0.; /// estimated signal clusters multiplicity on the selected multiplicity layer + float noisePerChip = 0.; /// imposed noise per chip (when enabled by configuration) + float cov[3] = {0.}; /// retained for compatibility; set to zero in single-layer mode + float chi2 = 0.; /// retained for compatibility; set to zero in single-layer mode + int nLayersUsed = 0; /// number of layers used by estimator (0/1 in single-layer mode) + uint32_t lastRandomSeed = 0; /// state of the gRandom before + FastMultEst(); + + static uint32_t getCurrentRandomSeed(); + int selectROFs(const std::array, NLayers>& rofs, + const std::array, NLayers>& clus, + const gsl::span trig, + uint32_t firstTForbit, + bool doStaggering, + const ROFOverlapTableN::View& overlapView, + ROFMaskTableN& sel); + void selectROFsWithVertices(const auto& vertices, const ROFOverlapTableN::View& overlapView, ROFMaskTableN& sel) const + { + const auto& multEstConf = FastMultEstConfig::Instance(); + if (!multEstConf.isVtxMultCutRequested()) { + return; + } + + for (const auto& vertex : vertices) { + if (!multEstConf.isPassingVtxMultCut(vertex.getNContributors())) { + const auto& timestamp{vertex.getTimeStamp()}; + for (int layer = 0; layer < NLayers; ++layer) { + uint32_t startROF = sel.getLayer(layer).getROF(timestamp.lower()); + uint32_t endROF = sel.getLayer(layer).getROF(timestamp.upper()); + for (uint32_t rof = startROF; rof <= endROF; ++rof) { + sel.setROFsEnabled(layer, rof, 0); + } + } + } + } + } + + int countClustersOnLayer(const gsl::span& clusters) const; + float process(int nClusters) + { + return FastMultEstConfig::Instance().imposeNoisePerChip > 0 ? processNoiseImposed(nClusters) : processNoiseFree(nClusters); + } + float processNoiseFree(int nClusters); + float processNoiseImposed(int nClusters); + float process(const gsl::span& clusters) + { + return process(countClustersOnLayer(clusters)); + } + static bool sSeedSet; +}; + +} // namespace o2::its + +#endif diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/FastMultEstConfig.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/FastMultEstConfig.h similarity index 58% rename from Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/FastMultEstConfig.h rename to Detectors/ITSMFT/ITS/tracking/include/ITStracking/FastMultEstConfig.h index c6bce50995a4b..1ab9796aa8cf6 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/FastMultEstConfig.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/FastMultEstConfig.h @@ -20,9 +20,7 @@ #include "CommonUtils/ConfigurableParamHelper.h" #include "ITSMFTReconstruction/ChipMappingITS.h" -namespace o2 -{ -namespace its +namespace o2::its { struct FastMultEstConfig : public o2::conf::ConfigurableParamHelper { static constexpr int NLayers = o2::itsmft::ChipMappingITS::NLayers; @@ -34,16 +32,19 @@ struct FastMultEstConfig : public o2::conf::ConfigurableParamHelper0 : set as is, <0 : use current time - bool preferTriggered = true; /// prefer ROFs with highest number of physics triggers - - bool isMultCutRequested() const { return cutMultClusLow >= 0.f && cutMultClusHigh > 0.f; }; - bool isVtxMultCutRequested() const { return cutMultVtxLow >= 0.f && cutMultVtxHigh > 0.f; }; + int cutMultClusLayer = NLayers - 1; /// layer used for cluster multiplicity selection (by default the outermost one) + float cutMultClusLow = 0; /// reject ROF with estimated cluster mult. below this value (no cut if <0) + float cutMultClusHigh = -1; /// reject ROF with estimated cluster mult. above this value (no cut if <0) + float cutMultVtxLow = -1; /// reject seed vertex if its multiplicity below this value (no cut if <0) + float cutMultVtxHigh = -1; /// reject seed vertex if its multiplicity above this value (no cut if <0) + float cutRandomFraction = -1.; /// apply random cut rejecting requested fraction + int randomSeed = 0; /// 0 - do not seet seed, >0 : set as is, <0 : use current time + bool preferTriggered = true; /// prefer ROFs with highest number of physics triggers + + bool isMultCutRequested() const noexcept { return cutMultClusLow >= 0.f && cutMultClusHigh > 0.f; }; + bool isVtxMultCutRequested() const noexcept { return cutMultVtxLow >= 0.f && cutMultVtxHigh > 0.f; }; + bool isRandCutRequested() const noexcept { return cutRandomFraction >= 0.; } + bool isRequested() const noexcept { return isMultCutRequested() || isVtxMultCutRequested() || isRandCutRequested(); } bool isPassingRandomRejection() const; bool isPassingMultCut(float mult) const { return mult >= cutMultClusLow && (mult <= cutMultClusHigh || cutMultClusHigh <= 0.f); } bool isPassingVtxMultCut(int mult) const { return mult >= cutMultVtxLow && (mult <= cutMultVtxHigh || cutMultVtxHigh <= 0.f); } @@ -51,7 +52,6 @@ struct FastMultEstConfig : public o2::conf::ConfigurableParamHelper -#include -#include #include -#include "DataFormatsITSMFT/ROFRecord.h" -#include "ITStracking/Configuration.h" -#include "ITStracking/ROframe.h" -#include "ITStracking/Label.h" -#include "ITStracking/Road.h" -#include "ITStracking/TrackingConfigParam.h" #include "ITSMFTBase/SegmentationAlpide.h" #include "ReconstructionDataFormats/BaseCluster.h" -#include "ITSMFTReconstruction/ChipMappingITS.h" #include "DataFormatsITSMFT/CompCluster.h" #include "DataFormatsITSMFT/TopologyDictionary.h" +#include "DataFormatsITSMFT/ROFRecord.h" // TODO this is just included since the alignment code include it now -namespace o2 +namespace o2::its::ioutils { -class MCCompLabel; - -namespace dataformats -{ -template -class MCTruthContainer; -} - -namespace its -{ - -namespace ioutils -{ 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; -void loadEventData(ROframe& events, gsl::span clusters, - gsl::span::iterator& pattIt, const itsmft::TopologyDictionary* dict, - const dataformats::MCTruthContainer* clsLabels = nullptr); -int loadROFrameData(const o2::itsmft::ROFRecord& rof, ROframe& events, gsl::span clusters, - gsl::span::iterator& pattIt, const itsmft::TopologyDictionary* dict, - const dataformats::MCTruthContainer* mClsLabels = nullptr); - void convertCompactClusters(gsl::span clusters, gsl::span::iterator& pattIt, std::vector>& output, const itsmft::TopologyDictionary* dict); -inline static const o2::itsmft::ChipMappingITS& getChipMappingITS() -{ - static const o2::itsmft::ChipMappingITS MP; - return MP; -} - -std::vector> loadLabels(const int, const std::string&); -void writeRoadsReport(std::ofstream&, std::ofstream&, std::ofstream&, const std::vector>>&, - const std::unordered_map&); - template o2::math_utils::Point3D extractClusterData(const itsmft::CompClusterExt& c, iterator& iter, const itsmft::TopologyDictionary* dict, T& sig2y, T& sig2z) { @@ -119,8 +80,6 @@ std::array extractClusterDataA(const itsmft::CompClusterExt& c, iterator& } } -} // namespace ioutils -} // namespace its -} // namespace o2 +} // namespace o2::its::ioutils #endif /* TRACKINGITSU_INCLUDE_EVENTLOADER_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/IndexTableUtils.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/IndexTableUtils.h index ed4027f77f360..4e8d5bcfea42a 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/IndexTableUtils.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/IndexTableUtils.h @@ -16,16 +16,18 @@ #ifndef TRACKINGITSU_INCLUDE_INDEXTABLEUTILS_H_ #define TRACKINGITSU_INCLUDE_INDEXTABLEUTILS_H_ -#include "ITStracking/Constants.h" -#include "ITStracking/Configuration.h" -#include "ITStracking/Definitions.h" +#include + +#include "ITStracking/Cluster.h" +#include "ITStracking/MathUtils.h" +#include "CommonConstants/MathConstants.h" #include "GPUCommonMath.h" #include "GPUCommonDef.h" -namespace o2 -{ -namespace its +namespace o2::its { + +template class IndexTableUtils { public: @@ -48,14 +50,15 @@ class IndexTableUtils int mNzBins = 0; int mNphiBins = 0; float mInversePhiBinSize = 0.f; - float mLayerZ[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; - float mInverseZBinSize[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; + std::array mLayerZ{}; + std::array mInverseZBinSize{}; }; +template template -inline void IndexTableUtils::setTrackingParameters(const T& params) +inline void IndexTableUtils::setTrackingParameters(const T& params) { - mInversePhiBinSize = params.PhiBins / constants::math::TwoPi; + mInversePhiBinSize = params.PhiBins / o2::constants::math::TwoPI; mNzBins = params.ZBins; mNphiBins = params.PhiBins; for (int iLayer{0}; iLayer < params.LayerZ.size(); ++iLayer) { @@ -66,28 +69,33 @@ inline void IndexTableUtils::setTrackingParameters(const T& params) } } -inline float IndexTableUtils::getInverseZCoordinate(const int layerIndex) const +template +inline float IndexTableUtils::getInverseZCoordinate(const int layerIndex) const { return 0.5f * mNzBins / mLayerZ[layerIndex]; } -GPUhdi() int IndexTableUtils::getZBinIndex(const int layerIndex, const float zCoordinate) const +template +GPUhdi() int IndexTableUtils::getZBinIndex(const int layerIndex, const float zCoordinate) const { return (zCoordinate + mLayerZ[layerIndex]) * mInverseZBinSize[layerIndex]; } -GPUhdi() int IndexTableUtils::getPhiBinIndex(const float currentPhi) const +template +GPUhdi() int IndexTableUtils::getPhiBinIndex(const float currentPhi) const { return (currentPhi * mInversePhiBinSize); } -GPUhdi() int IndexTableUtils::getBinIndex(const int zIndex, const int phiIndex) const +template +GPUhdi() int IndexTableUtils::getBinIndex(const int zIndex, const int phiIndex) const { - return o2::gpu::GPUCommonMath::Min(phiIndex * mNzBins + zIndex, mNzBins * mNphiBins - 1); + return o2::gpu::GPUCommonMath::Min(phiIndex * mNzBins + zIndex, (mNzBins * mNphiBins) - 1); } -GPUhdi() int IndexTableUtils::countRowSelectedBins(const int* indexTable, const int phiBinIndex, - const int minZBinIndex, const int maxZBinIndex) const +template +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}; @@ -95,14 +103,35 @@ GPUhdi() int IndexTableUtils::countRowSelectedBins(const int* indexTable, const return indexTable[maxBinIndex] - indexTable[firstBinIndex]; } -GPUhdi() void IndexTableUtils::print() const +template +GPUhdi() void IndexTableUtils::print() const { printf("NzBins: %d, NphiBins: %d, InversePhiBinSize: %f\n", mNzBins, mNphiBins, mInversePhiBinSize); - for (int iLayer{0}; iLayer < 7; ++iLayer) { + for (int iLayer{0}; iLayer < nLayers; ++iLayer) { printf("Layer %d: Z: %f, InverseZBinSize: %f\n", iLayer, mLayerZ[iLayer], mInverseZBinSize[iLayer]); } } -} // namespace its -} // namespace o2 +template +GPUhdi() int4 getBinsRect(const Cluster& currentCluster, const int layerIndex, + const float z1, const float z2, const float maxdeltaz, const float maxdeltaphi, + const IndexTableUtils& utils) +{ + const float zRangeMin = o2::gpu::GPUCommonMath::Min(z1, z2) - maxdeltaz; + const float phiRangeMin = (maxdeltaphi > o2::constants::math::PI) ? 0.f : currentCluster.phi - maxdeltaphi; + const float zRangeMax = o2::gpu::GPUCommonMath::Max(z1, z2) + maxdeltaz; + const float phiRangeMax = (maxdeltaphi > o2::constants::math::PI) ? o2::constants::math::TwoPI : currentCluster.phi + maxdeltaphi; + + if (zRangeMax < -utils.getLayerZ(layerIndex) || + zRangeMin > utils.getLayerZ(layerIndex) || zRangeMin > zRangeMax) { + return int4{-1, -1, -1, -1}; + } + + return int4{o2::gpu::GPUCommonMath::Max(0, utils.getZBinIndex(layerIndex, zRangeMin)), + utils.getPhiBinIndex(math_utils::getNormalizedPhi(phiRangeMin)), + o2::gpu::GPUCommonMath::Min(utils.getNzBins() - 1, utils.getZBinIndex(layerIndex, zRangeMax)), + utils.getPhiBinIndex(math_utils::getNormalizedPhi(phiRangeMax))}; +} + +} // namespace o2::its #endif /* TRACKINGITSU_INCLUDE_INDEXTABLEUTILS_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/LayerMask.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/LayerMask.h new file mode 100644 index 0000000000000..9fe9894b3b457 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/LayerMask.h @@ -0,0 +1,115 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef TRACKINGITSU_INCLUDE_LAYERMASK_H_ +#define TRACKINGITSU_INCLUDE_LAYERMASK_H_ + +#include +#include + +#ifndef GPUCA_GPUCODE +#include +#include +#endif + +#include "GPUCommonDef.h" +#include "GPUCommonMath.h" +#include "ITStracking/Constants.h" + +namespace o2::its +{ + +struct LayerMask { + GPUhdDefault() constexpr LayerMask() noexcept = default; + GPUhdDefault() constexpr LayerMask(uint16_t mask) noexcept : mBits{mask} {} + GPUhdDefault() constexpr LayerMask(int layer0, int layer1, int layer2) noexcept + : mBits{static_cast((uint16_t(1) << layer0) | (uint16_t(1) << layer1) | (uint16_t(1) << layer2))} + { + } + GPUhdi() constexpr operator uint16_t() const noexcept { return mBits; } + GPUhdi() constexpr uint16_t value() const noexcept { return mBits; } + GPUhdi() constexpr void set(int layer) noexcept { mBits |= (uint16_t(1) << layer); } + + GPUhdi() LayerMask operator~() const noexcept { return LayerMask{static_cast(~mBits)}; } + GPUhdi() LayerMask operator&(LayerMask other) const noexcept { return LayerMask{static_cast(mBits & other.mBits)}; } + GPUhdi() LayerMask operator|(LayerMask other) const noexcept { return LayerMask{static_cast(mBits | other.mBits)}; } + GPUhdi() LayerMask& operator&=(LayerMask other) noexcept + { + mBits &= other.mBits; + return *this; + } + GPUhdi() LayerMask& operator|=(LayerMask other) noexcept + { + mBits |= other.mBits; + return *this; + } + + GPUhdi() bool empty() const noexcept { return mBits == 0; } + GPUhdi() bool has(int layer) const noexcept { return mBits & (uint16_t(1) << layer); } + GPUhdi() bool isSubsetOf(LayerMask allowed) const noexcept { return (*this & ~allowed).empty(); } + GPUhdi() bool isAllowedHoleMask(int maxHoles, LayerMask allowedHoleMask) const noexcept + { + const int allowedHoles = maxHoles > 0 ? maxHoles : 0; + return count() <= allowedHoles && isSubsetOf(allowedHoleMask); + } + GPUhdi() bool isAllowed(int maxHoles, LayerMask allowedHoleMask) const noexcept + { + return holeMask().isAllowedHoleMask(maxHoles, allowedHoleMask); + } + GPUhdi() int length() const noexcept { return empty() ? 0 : last() - first() + 1; } + GPUhdi() int count() const noexcept { return static_cast(o2::gpu::GPUCommonMath::Popcount(mBits)); } + GPUhdi() int first() const noexcept { return mBits ? static_cast(o2::gpu::GPUCommonMath::Ctz(mBits)) : constants::UnusedIndex; } + GPUhdi() int last() const noexcept { return mBits ? 31 - static_cast(o2::gpu::GPUCommonMath::Clz(mBits)) : constants::UnusedIndex; } + GPUhdi() LayerMask holeMask() const noexcept + { + return empty() ? LayerMask{0} : (span(first(), last()) & ~(*this)); + } + + GPUhdi() int slot(int layer) const noexcept + { + if (!has(layer)) { + return constants::UnusedIndex; + } + const uint32_t lowerLayers = (uint32_t(1) << layer) - 1; + return static_cast(o2::gpu::GPUCommonMath::Popcount(static_cast(mBits) & lowerLayers)); + } + + static GPUhdi() LayerMask span(int fromLayer, int toLayer) noexcept + { + if (fromLayer > toLayer) { + return 0; + } + const uint32_t upper = (uint32_t(1) << (toLayer + 1)) - 1; + const uint32_t lower = (uint32_t(1) << fromLayer) - 1; + return static_cast(upper & ~lower); + } + + static GPUhdi() LayerMask skipped(int fromLayer, int toLayer) noexcept + { + return (toLayer - fromLayer <= 1) ? LayerMask{0} : span(fromLayer + 1, toLayer - 1); + } + +#ifndef GPUCA_GPUCODE + std::string asString() const { return fmt::format("{:016b}", mBits); } +#endif + + private: + uint16_t mBits{0}; +}; + +static_assert(std::is_standard_layout_v); +static_assert(std::is_trivially_copyable_v); +static_assert(sizeof(LayerMask) == sizeof(uint16_t)); +static_assert(alignof(LayerMask) == alignof(uint16_t)); + +} // namespace o2::its + +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/LineVertexerHelpers.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/LineVertexerHelpers.h new file mode 100644 index 0000000000000..0e3807aba8efb --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/LineVertexerHelpers.h @@ -0,0 +1,46 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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_TRACKING_LINE_VERTEXER_HELPERS_H_ +#define O2_ITS_TRACKING_LINE_VERTEXER_HELPERS_H_ + +#include +#include + +#include "ITStracking/BoundedAllocator.h" +#include "ITStracking/ClusterLines.h" + +namespace o2::its::line_vertexer +{ + +struct Settings { + float beamX = 0.f; + float beamY = 0.f; + float pairCut = 0.f; + float pairCut2 = 0.f; + float clusterCut = 0.f; + float coarseZWindow = 0.f; + float seedDedupZCut = 0.f; + float refitDedupZCut = 0.f; + float duplicateZCut = 0.f; + float duplicateDistance2Cut = 0.f; + float finalSelectionZCut = 0.f; + float maxZ = 0.f; + int seedMemberRadiusTime = 1; + int seedMemberRadiusZ = 2; + std::shared_ptr memoryPool; +}; + +bounded_vector buildClusters(std::span lines, const Settings& settings); + +} // namespace o2::its::line_vertexer + +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/MathUtils.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/MathUtils.h index 9093609144283..950d8c0a9117f 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/MathUtils.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/MathUtils.h @@ -1,4 +1,4 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. // See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. // All rights not expressly granted are reserved. // @@ -13,92 +13,116 @@ /// \brief /// -#ifndef TRACKINGITSU_INCLUDE_CAUTILS_H_ -#define TRACKINGITSU_INCLUDE_CAUTILS_H_ +#ifndef O2_ITS_TRACKING_MATHUTILS_H_ +#define O2_ITS_TRACKING_MATHUTILS_H_ -#ifndef GPUCA_GPUCODE_DEVICE -#include -#include -#include -#include -#endif +#include -#include "MathUtils/Utils.h" +#include "CommonConstants/MathConstants.h" #include "ITStracking/Constants.h" +#include "MathUtils/Utils.h" #include "GPUCommonMath.h" #include "GPUCommonDef.h" -namespace o2 +namespace o2::its::math_utils { -namespace its + +GPUhdi() float computePhi(float x, float y) { + return o2::math_utils::fastATan2(-y, -x) + o2::constants::math::PI; +} -namespace math_utils +GPUhdi() constexpr float hypot(float x, float y) { -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); -GPUhdni() float computeTanDipAngle(float x1, float y1, float x2, float y2, float z1, float z2); + return o2::gpu::CAMath::Hypot(x, y); +} -} // namespace math_utils +GPUhdi() constexpr float getNormalizedPhi(float phi) +{ + phi -= o2::constants::math::TwoPI * o2::gpu::CAMath::Floor(phi * (1.f / o2::constants::math::TwoPI)); + return phi; +} + +GPUhdi() float computeCurvature(float x1, float y1, float x2, float y2, float x3, float y3) +{ + // in case the triangle is degenerate we return infinite curvature. + const float area = ((x2 - x1) * (y3 - y1)) - ((x3 - x1) * (y2 - y1)); + if (o2::gpu::CAMath::Abs(area) < constants::Tolerance) { + return o2::constants::math::Almost0; + } + const float dx1 = x2 - x1, dy1 = y2 - y1; + const float dx2 = x3 - x2, dy2 = y3 - y2; + const float dx3 = x1 - x3, dy3 = y1 - y3; + const float d1 = o2::gpu::CAMath::Sqrt((dx1 * dx1) + (dy1 * dy1)); + const float d2 = o2::gpu::CAMath::Sqrt((dx2 * dx2) + (dy2 * dy2)); + const float d3 = o2::gpu::CAMath::Sqrt((dx3 * dx3) + (dy3 * dy3)); + return -2.f * area / (d1 * d2 * d3); +} + +GPUhdi() float computeCurvatureCentreX(float x1, float y1, float x2, float y2, float x3, float y3) +{ + // in case the triangle is degenerate we return set the centre to infinity. + float dx21 = x2 - x1, dx32 = x3 - x2; + if (o2::gpu::CAMath::Abs(dx21) < o2::its::constants::Tolerance || + o2::gpu::CAMath::Abs(dx32) < o2::its::constants::Tolerance) { // add small offset + x2 += 1e-4; + dx21 = x2 - x1; + dx32 = x3 - x2; + } + const float k1 = (y2 - y1) / dx21, k2 = (y3 - y2) / dx32; + if (o2::gpu::CAMath::Abs(k2 - k1) < o2::its::constants::Tolerance) { + return o2::constants::math::VeryBig; + } + return 0.5f * (k1 * k2 * (y1 - y3) + k2 * (x1 + x2) - k1 * (x2 + x3)) / (k2 - k1); +} -GPUhdi() float math_utils::computePhi(const float x, const float y) +GPUhdi() float computeTanDipAngle(float x1, float y1, float x2, float y2, float z1, float z2) { - //return o2::gpu::CAMath::ATan2(-yCoordinate, -xCoordinate) + constants::math::Pi; - return o2::math_utils::fastATan2(-y, -x) + constants::math::Pi; + // in case the points vertically align we go to pos/neg infinity. + const float d = o2::gpu::CAMath::Hypot(x1 - x2, y1 - y2); + if (o2::gpu::CAMath::Abs(d) < o2::its::constants::Tolerance) { + return ((z1 > z2) ? -1.f : 1.f) * o2::constants::math::VeryBig; + } + return (z1 - z2) / d; } -GPUhdi() float math_utils::hypot(const float x, const float y) +GPUhdi() float smallestAngleDifference(float a, float b) { - return o2::gpu::CAMath::Sqrt(x * x + y * y); + return o2::gpu::CAMath::Remainderf(b - a, o2::constants::math::TwoPI); } -GPUhdi() constexpr float math_utils::getNormalizedPhi(const float phi) +GPUhdi() bool isPhiDifferenceBelow(const float phiA, const float phiB, const float phiCut) { - return (phi < 0) ? phi + constants::math::TwoPi : (phi > constants::math::TwoPi) ? phi - constants::math::TwoPi - : phi; + const float deltaPhi = o2::gpu::CAMath::Abs(phiA - phiB); + return deltaPhi < phiCut || deltaPhi > o2::constants::math::TwoPI - phiCut; } -GPUhdi() constexpr float3 math_utils::crossProduct(const float3& firstVector, const float3& secondVector) +GPUhdi() constexpr float Sq(float v) { + return v * v; +} - return float3{(firstVector.y * secondVector.z) - (firstVector.z * secondVector.y), - (firstVector.z * secondVector.x) - (firstVector.x * secondVector.z), - (firstVector.x * secondVector.y) - (firstVector.y * secondVector.x)}; +GPUhdi() constexpr float SqSum(float v, float w) +{ + return Sq(v) + Sq(w); } -GPUhdi() float math_utils::computeCurvature(float x1, float y1, float x2, float y2, float x3, float y3) +GPUhdi() constexpr float SqSum(float u, float v, float w) { - const float d = (x2 - x1) * (y3 - y2) - (x3 - x2) * (y2 - y1); - const float a = - 0.5f * ((y3 - y2) * (y2 * y2 - y1 * y1 + x2 * x2 - x1 * x1) - (y2 - y1) * (y3 * y3 - y2 * y2 + x3 * x3 - x2 * x2)); - const float b = - 0.5f * ((x2 - x1) * (y3 * y3 - y2 * y2 + x3 * x3 - x2 * x2) - (x3 - x2) * (y2 * y2 - y1 * y1 + x2 * x2 - x1 * x1)); - const float den2 = (d * x1 - a) * (d * x1 - a) + (d * y1 - b) * (d * y1 - b); - return den2 > 0.f ? -1.f * d / o2::gpu::CAMath::Sqrt(den2) : 0.f; + return Sq(u) + SqSum(v, w); } -GPUhdi() float math_utils::computeCurvatureCentreX(float x1, float y1, float x2, float y2, float x3, float y3) +GPUhdi() constexpr float SqDiff(float x, float y) { - float dx21 = x2 - x1, dx32 = x3 - x2; - if (dx21 == 0.f || dx32 == 0.f) { // add small offset - x2 += 1e-4; - dx21 = x2 - x1; - dx32 = x3 - x2; - } - float k1 = (y2 - y1) / dx21, k2 = (y3 - y2) / dx32; - return (k1 != k2) ? 0.5f * (k1 * k2 * (y1 - y3) + k2 * (x1 + x2) - k1 * (x2 + x3)) / (k2 - k1) : 1e5; + return Sq(x - y); } -GPUhdi() float math_utils::computeTanDipAngle(float x1, float y1, float x2, float y2, float z1, float z2) +GPUhdi() float MSangle(float mass, float p, float xX0) { - return (z1 - z2) / o2::gpu::CAMath::Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + float beta = p / o2::gpu::CAMath::Hypot(mass, p); + return 0.0136f * o2::gpu::CAMath::Sqrt(xX0) * (1.f + 0.038f * o2::gpu::CAMath::Log(xX0)) / (beta * p); } -} // namespace its -} // namespace o2 +} // namespace o2::its::math_utils -#endif /* TRACKINGITSU_INCLUDE_CAUTILS_H_ */ +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ROFLookupTables.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ROFLookupTables.h new file mode 100644 index 0000000000000..ce20169e36c64 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ROFLookupTables.h @@ -0,0 +1,850 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef TRACKINGITSU_INCLUDE_ROFOVERLAPTABLE_H_ +#define TRACKINGITSU_INCLUDE_ROFOVERLAPTABLE_H_ + +#include +#include +#include +#include +#include +#include + +#ifndef GPUCA_GPUCODE +#include +#include "Framework/Logger.h" +#endif + +#include "CommonConstants/LHCConstants.h" +#include "CommonDataFormat/RangeReference.h" +#include "DataFormatsITS/TimeEstBC.h" +#include "DataFormatsITS/Vertex.h" +#include "GPUCommonMath.h" +#include "GPUCommonDef.h" + +namespace o2::its +{ + +// Layer timing definition +struct LayerTiming { + using BCType = TimeStampType; + BCType mNROFsTF{0}; // number of ROFs per timeframe + BCType mROFLength{0}; // ROF length in BC + BCType mROFDelay{0}; // delay of ROFs wrt start of first orbit in TF in BC + BCType mROFBias{0}; // bias wrt to the LHC clock in BC + BCType mROFAddTimeErr{0}; // additionally imposed uncertainty on ROF time in BC + + // return start of ROF in BC + // this does not account for the opt. error! + GPUhdi() BCType getROFStartInBC(BCType rofId) const noexcept + { + assert(rofId < mNROFsTF && rofId >= 0); + return (mROFLength * rofId) + mROFDelay + mROFBias; + } + + // return end of ROF in BCs + // this does not account for the opt. error! + GPUhdi() BCType getROFEndInBC(BCType rofId) const noexcept + { + assert(rofId < mNROFsTF); + return getROFStartInBC(rofId) + mROFLength; + } + + // return (clamped) time-interval of rof + GPUhdi() TimeEstBC getROFTimeBounds(BCType rofId, bool withError = false) const noexcept + { + if (withError) { + int64_t start = getROFStartInBC(rofId); + int64_t end = getROFEndInBC(rofId); + start = o2::gpu::CAMath::Max(start - mROFAddTimeErr, int64_t(0)); + end += mROFAddTimeErr; + return {static_cast(start), static_cast(end - start)}; + } + return {getROFStartInBC(rofId), static_cast(mROFLength)}; + } + + // return which ROF this BC belongs to + GPUhi() BCType getROF(BCType bc) const noexcept + { + const BCType offset = mROFDelay + mROFBias; + if (bc <= offset) { + return 0; + } + return (bc - offset) / mROFLength; + } + + // return which ROF this timestamp belongs by its lower edge + GPUhi() BCType getROF(TimeStamp ts) const noexcept + { + const BCType offset = mROFDelay + mROFBias; + const BCType bc = (ts.getTimeStamp() < ts.getTimeStampError()) ? BCType(0) : static_cast(o2::gpu::CAMath::Floor(ts.getTimeStamp() - ts.getTimeStampError())); + if (bc <= offset) { + return 0; + } + return (bc - offset) / mROFLength; + } + +#ifndef GPUCA_GPUCODE + GPUh() std::string asString() const + { + return std::format("NROFsPerTF {:4} ROFLength {:4} ({:4} per Orbit) ROFDelay {:4} ROFBias {:4} ROFAddTimeErr {:4}", mNROFsTF, mROFLength, (o2::constants::lhc::LHCMaxBunches / mROFLength), mROFDelay, mROFBias, mROFAddTimeErr); + } + + GPUh() void print() const + { + LOG(info) << asString(); + } +#endif +}; + +// Base class for lookup to define layers +template +class LayerTimingBase +{ + protected: + LayerTiming mLayers[NLayers]; + + public: + using T = LayerTiming::BCType; + LayerTimingBase() = default; + + GPUh() void defineLayer(int32_t layer, T nROFsTF, T rofLength, T rofDelay, T rofBias, T rofTE) + { + assert(layer >= 0 && layer < NLayers); + mLayers[layer] = {nROFsTF, rofLength, rofDelay, rofBias, rofTE}; + } + + GPUh() void defineLayer(int32_t layer, const LayerTiming& timing) + { + assert(layer >= 0 && layer < NLayers); + mLayers[layer] = timing; + } + + GPUhdi() const LayerTiming& getLayer(int32_t layer) const + { + assert(layer >= 0 && layer < NLayers); + return mLayers[layer]; + } + + GPUhdi() constexpr int32_t getEntries() noexcept { return NLayers; } + +#ifndef GPUCA_GPUCODE + GPUh() void print() const + { + LOGP(info, "Imposed time structure:"); + for (int32_t iL{0}; iL < NLayers; ++iL) { + LOGP(info, "\tLayer:{} {}", iL, mLayers[iL].asString()); + } + } +#endif +}; + +// GPU friendly view of the table below +template +struct ROFOverlapTableView { + const TableEntry* mFlatTable{nullptr}; + const TableIndex* mIndices{nullptr}; + const LayerTiming* mLayers{nullptr}; + + GPUhdi() const LayerTiming& getLayer(int32_t layer) const noexcept + { + assert(layer >= 0 && layer < NLayers); + return mLayers[layer]; + } + + GPUh() int32_t getClock() const noexcept + { + // we take the fastest layer as clock + int32_t fastest = 0; + uint32_t maxNROFs{0}; + for (int32_t iL{0}; iL < NLayers; ++iL) { + const auto& layer = getLayer(iL); + // by definition the fastest layer has the most ROFs + // this also solves the problem of a delay large than ROFLength + // if mNROFsTF is correct + if (layer.mNROFsTF > maxNROFs) { + fastest = iL; + maxNROFs = layer.mNROFsTF; + } + } + return fastest; + } + + GPUh() const LayerTiming& getClockLayer() const noexcept + { + return mLayers[getClock()]; + } + + GPUhdi() const TableEntry& getOverlap(int32_t from, int32_t to, size_t rofIdx) const noexcept + { + assert(from < NLayers && to < NLayers); + const size_t linearIdx = (from * NLayers) + to; + const auto& idx = mIndices[linearIdx]; + assert(rofIdx < idx.getEntries()); + return mFlatTable[idx.getFirstEntry() + rofIdx]; + } + + GPUhdi() bool doROFsOverlap(int32_t layer0, size_t rof0, int32_t layer1, size_t rof1) const noexcept + { + if (layer0 == layer1) { // layer is compatible with itself + return rof0 == rof1; + } + + assert(layer0 < NLayers && layer1 < NLayers); + const size_t linearIdx = (layer0 * NLayers) + layer1; + const auto& idx = mIndices[linearIdx]; + + if (rof0 >= idx.getEntries()) { + return false; + } + + const auto& overlap = mFlatTable[idx.getFirstEntry() + rof0]; + + if (overlap.getEntries() == 0) { + return false; + } + + const size_t firstCompatible = overlap.getFirstEntry(); + const size_t lastCompatible = firstCompatible + overlap.getEntries() - 1; + return rof1 >= firstCompatible && rof1 <= lastCompatible; + } + + GPUhdi() TimeEstBC getTimeStamp(int32_t layer0, size_t rof0, int32_t layer1, size_t rof1) const noexcept + { + assert(layer0 < NLayers && layer1 < NLayers); + assert(doROFsOverlap(layer0, rof0, layer1, rof1)); + // retrieves the combined timestamp + // e.g., taking one cluster from rof0 and one from rof1 + // and constructing a tracklet (doublet) what is its time + // this assumes that the rofs overlap, e.g. doROFsOverlap -> true + // get timestamp including margins from rof0 and rof1 + const auto t0 = mLayers[layer0].getROFTimeBounds(rof0, true); + const auto t1 = mLayers[layer1].getROFTimeBounds(rof1, true); + return t0 + t1; + } + +#ifndef GPUCA_GPUCODE + /// Print functions + GPUh() void printAll() const + { + for (int32_t i = 0; i < NLayers; ++i) { + for (int32_t j = 0; j < NLayers; ++j) { + if (i != j) { + printMapping(i, j); + } + } + } + printSummary(); + } + + GPUh() void printMapping(int32_t from, int32_t to) const + { + if (from == to) { + LOGP(error, "No self-lookup supported"); + return; + } + + constexpr int w_index = 10; + constexpr int w_first = 12; + constexpr int w_last = 12; + constexpr int w_count = 10; + + LOGF(info, "Overlap mapping: Layer %d -> Layer %d", from, to); + LOGP(info, "From: {}", mLayers[from].asString()); + LOGP(info, "To : {}", mLayers[to].asString()); + LOGF(info, "%*s | %*s | %*s | %*s", w_index, "ROF.index", w_first, "First.ROF", w_last, "Last.ROF", w_count, "Count"); + LOGF(info, "%.*s-+-%.*s-+-%.*s-+-%.*s", w_index, "----------", w_first, "------------", w_last, "------------", w_count, "----------"); + + const size_t linearIdx = (from * NLayers) + to; + const auto& idx = mIndices[linearIdx]; + for (int32_t i = 0; i < idx.getEntries(); ++i) { + const auto& overlap = getOverlap(from, to, i); + LOGF(info, "%*d | %*d | %*d | %*d", w_index, i, w_first, overlap.getFirstEntry(), w_last, overlap.getEntriesBound() - 1, w_count, overlap.getEntries()); + } + } + + GPUh() void printSummary() const + { + uint32_t totalEntries{0}; + size_t flatTableSize{0}; + + for (int32_t i = 0; i < NLayers; ++i) { + for (int32_t j = 0; j < NLayers; ++j) { + if (i != j) { + const size_t linearIdx = (i * NLayers) + j; + const auto& idx = mIndices[linearIdx]; + totalEntries += idx.getEntries(); + flatTableSize += idx.getEntries(); + } + } + } + + for (int32_t i = 0; i < NLayers; ++i) { + mLayers[i].print(); + } + + const uint32_t totalBytes = (flatTableSize * sizeof(TableEntry)) + (static_cast(NLayers * NLayers) * sizeof(TableIndex)); + LOGF(info, "------------------------------------------------------------"); + LOGF(info, "Total overlap table size: %u entries", totalEntries); + LOGF(info, "Flat table size: %zu entries", flatTableSize); + LOGF(info, "Total view size: %u bytes", totalBytes); + LOGF(info, "------------------------------------------------------------"); + } +#endif +}; + +// Precalculated lookup table to find overlapping ROFs in another layer given a ROF index in the current layer +template +class ROFOverlapTable : public LayerTimingBase +{ + public: + using T = LayerTimingBase::T; + using TableEntry = dataformats::RangeReference; + using TableIndex = dataformats::RangeReference; + + using View = ROFOverlapTableView; + ROFOverlapTable() = default; + + GPUh() void init() + { + std::vector table[NLayers][NLayers]; + for (int32_t i{0}; i < NLayers; ++i) { + for (int32_t j{0}; j < NLayers; ++j) { + if (i != j) { // we do not need self-lookup + buildMapping(i, j, table[i][j]); + } + } + } + flatten(table); + } + + GPUh() View getView() const + { + View view; + view.mFlatTable = mFlatTable.data(); + view.mIndices = mIndices; + view.mLayers = this->mLayers; + return view; + } + + GPUh() View getDeviceView(const TableEntry* deviceFlatTablePtr, const TableIndex* deviceIndicesPtr, const LayerTiming* deviceLayerTimingPtr) const + { + View view; + view.mFlatTable = deviceFlatTablePtr; + view.mIndices = deviceIndicesPtr; + view.mLayers = deviceLayerTimingPtr; + return view; + } + + GPUh() size_t getFlatTableSize() const noexcept { return mFlatTable.size(); } + static GPUh() constexpr size_t getIndicesSize() { return static_cast(NLayers * NLayers); } + + private: + GPUh() void buildMapping(int32_t from, int32_t to, std::vector& table) + { + const auto& layerFrom = this->mLayers[from]; + const auto& layerTo = this->mLayers[to]; + table.resize(layerFrom.mNROFsTF); + + for (int32_t iROF{0}; iROF < layerFrom.mNROFsTF; ++iROF) { + int64_t fromStart = o2::gpu::CAMath::Max((int64_t)layerFrom.getROFStartInBC(iROF) - (int64_t)layerFrom.mROFAddTimeErr, int64_t(0)); + int64_t fromEnd = (int64_t)layerFrom.getROFEndInBC(iROF) + layerFrom.mROFAddTimeErr; + + int32_t firstROFTo = o2::gpu::CAMath::Max(0, (int32_t)((fromStart - (int64_t)layerTo.mROFAddTimeErr - (int64_t)layerTo.mROFDelay - (int64_t)layerTo.mROFBias) / (int64_t)layerTo.mROFLength)); + auto lastROFTo = (int32_t)((fromEnd + (int64_t)layerTo.mROFAddTimeErr - (int64_t)layerTo.mROFDelay - (int64_t)layerTo.mROFBias - 1) / (int64_t)layerTo.mROFLength); + firstROFTo = o2::gpu::CAMath::Max(0, firstROFTo); + lastROFTo = o2::gpu::CAMath::Min((int32_t)layerTo.mNROFsTF - 1, lastROFTo); + + while (firstROFTo <= lastROFTo) { + int64_t toStart = o2::gpu::CAMath::Max((int64_t)layerTo.getROFStartInBC(firstROFTo) - (int64_t)layerTo.mROFAddTimeErr, int64_t(0)); + int64_t toEnd = (int64_t)layerTo.getROFEndInBC(firstROFTo) + layerTo.mROFAddTimeErr; + if (toEnd > fromStart && toStart < fromEnd) { + break; + } + ++firstROFTo; + } + while (lastROFTo >= firstROFTo) { + int64_t toStart = o2::gpu::CAMath::Max((int64_t)layerTo.getROFStartInBC(lastROFTo) - (int64_t)layerTo.mROFAddTimeErr, int64_t(0)); + int64_t toEnd = (int64_t)layerTo.getROFEndInBC(lastROFTo) + layerTo.mROFAddTimeErr; + if (toEnd > fromStart && toStart < fromEnd) { + break; + } + --lastROFTo; + } + int32_t count = (firstROFTo <= lastROFTo) ? (lastROFTo - firstROFTo + 1) : 0; + table[iROF] = {static_cast(firstROFTo), static_cast(count)}; + } + } + + GPUh() void flatten(const std::vector table[NLayers][NLayers]) + { + size_t total{0}; + for (int32_t i{0}; i < NLayers; ++i) { + for (int32_t j{0}; j < NLayers; ++j) { + if (i != j) { // we do not need self-lookup + total += table[i][j].size(); + } + } + } + + mFlatTable.reserve(total); + + for (int32_t i{0}; i < NLayers; ++i) { + for (int32_t j{0}; j < NLayers; ++j) { + size_t idx = (i * NLayers) + j; + if (i != j) { + mIndices[idx].setFirstEntry(static_cast(mFlatTable.size())); + mIndices[idx].setEntries(static_cast(table[i][j].size())); + mFlatTable.insert(mFlatTable.end(), table[i][j].begin(), table[i][j].end()); + } else { + mIndices[idx] = {0, 0}; + } + } + } + } + + TableIndex mIndices[NLayers * NLayers]; + std::vector mFlatTable; +}; + +// GPU friendly view of the table below +template +struct ROFVertexLookupTableView { + const TableEntry* mFlatTable{nullptr}; + const TableIndex* mIndices{nullptr}; + const LayerTiming* mLayers{nullptr}; + + GPUhdi() const LayerTiming& getLayer(int32_t layer) const noexcept + { + assert(layer >= 0 && layer < NLayers); + return mLayers[layer]; + } + + GPUhdi() const TableEntry& getVertices(int32_t layer, size_t rofIdx) const noexcept + { + assert(layer < NLayers); + const auto& idx = mIndices[layer]; + assert(rofIdx < idx.getEntries()); + return mFlatTable[idx.getFirstEntry() + rofIdx]; + } + + GPUh() int32_t getMaxVerticesPerROF() const noexcept + { + int32_t maxCount = 0; + for (int32_t layer = 0; layer < NLayers; ++layer) { + const auto& idx = mIndices[layer]; + for (int32_t i = 0; i < idx.getEntries(); ++i) { + const auto& entry = mFlatTable[idx.getFirstEntry() + i]; + maxCount = o2::gpu::CAMath::Max(maxCount, static_cast(entry.getEntries())); + } + } + return maxCount; + } + + // Check if a specific vertex is compatible with a given ROF + GPUhdi() bool isVertexCompatible(int32_t layer, size_t rofIdx, const Vertex& vertex) const noexcept + { + assert(layer < NLayers); + const auto& layerDef = mLayers[layer]; + int64_t rofLower = o2::gpu::CAMath::Max((int64_t)layerDef.getROFStartInBC(rofIdx) - (int64_t)layerDef.mROFAddTimeErr, int64_t(0)); + int64_t rofUpper = (int64_t)layerDef.getROFEndInBC(rofIdx) + layerDef.mROFAddTimeErr; + auto vLower = (int64_t)vertex.getTimeStamp().lower(); + auto vUpper = (int64_t)vertex.getTimeStamp().upper(); + return vUpper >= rofLower && vLower < rofUpper; + } + +#ifndef GPUCA_GPUCODE + GPUh() void printAll() const + { + for (int32_t i = 0; i < NLayers; ++i) { + printLayer(i); + } + printSummary(); + } + + GPUh() void printLayer(int32_t layer) const + { + constexpr int w_rof = 10; + constexpr int w_first = 12; + constexpr int w_last = 12; + constexpr int w_count = 10; + + LOGF(info, "Vertex lookup: Layer %d", layer); + LOGF(info, "%*s | %*s | %*s | %*s", w_rof, "ROF.index", w_first, "First.Vtx", w_last, "Last.Vtx", w_count, "Count"); + LOGF(info, "%.*s-+-%.*s-+-%.*s-+-%.*s", w_rof, "----------", w_first, "------------", w_last, "------------", w_count, "----------"); + + const auto& idx = mIndices[layer]; + for (int32_t i = 0; i < idx.getEntries(); ++i) { + const auto& entry = mFlatTable[idx.getFirstEntry() + i]; + int first = entry.getFirstEntry(); + int count = entry.getEntries(); + int last = first + count - 1; + LOGF(info, "%*d | %*d | %*d | %*d", w_rof, i, w_first, first, w_last, last, w_count, count); + } + } + + GPUh() void printSummary() const + { + uint32_t totalROFs{0}; + uint32_t totalVertexRefs{0}; + + for (int32_t i = 0; i < NLayers; ++i) { + const auto& idx = mIndices[i]; + totalROFs += idx.getEntries(); + + for (int32_t j = 0; j < idx.getEntries(); ++j) { + const auto& entry = mFlatTable[idx.getFirstEntry() + j]; + totalVertexRefs += entry.getEntries(); + } + } + + const uint32_t totalBytes = (totalROFs * sizeof(TableEntry)) + (NLayers * sizeof(TableIndex)); + LOGF(info, "------------------------------------------------------------"); + LOGF(info, "Total ROFs in table: %u", totalROFs); + LOGF(info, "Total vertex references: %u", totalVertexRefs); + LOGF(info, "Total view size: %u bytes", totalBytes); + LOGF(info, "------------------------------------------------------------"); + } +#endif +}; + +// Precalculated lookup table to find vertices compatible with ROFs +// Given a layer and ROF index, returns the range of vertices that overlap in time. +// The vertex time is defined as symmetrical [t0-e,t0+e] +// It needs to be guaranteed that the input vertices are sorted by their lower-bound! +// additionally compatibliyty has to be queried per vertex! +template +class ROFVertexLookupTable : public LayerTimingBase +{ + public: + using T = LayerTimingBase::T; + using BCType = LayerTiming::BCType; + using TableEntry = dataformats::RangeReference; + using TableIndex = dataformats::RangeReference; + using View = ROFVertexLookupTableView; + + ROFVertexLookupTable() = default; + + GPUh() size_t getFlatTableSize() const noexcept { return mFlatTable.size(); } + static GPUh() constexpr size_t getIndicesSize() { return NLayers; } + + // Build the lookup table given a sorted array of vertices + // vertices must be sorted by timestamp, then by error (secondary) + GPUh() void init(const Vertex* vertices, size_t nVertices) + { + if (nVertices > std::numeric_limits::max()) { + LOGF(fatal, "too many vertices %zu, max supported is %u", nVertices, std::numeric_limits::max()); + } + + std::vector table[NLayers]; + for (int32_t layer{0}; layer < NLayers; ++layer) { + buildMapping(layer, vertices, nVertices, table[layer]); + } + flatten(table); + } + + // Pre-allocated needed memory, then use update(...) + GPUh() void init() + { + size_t total{0}; + for (int32_t layer{0}; layer < NLayers; ++layer) { + total += this->mLayers[layer].mNROFsTF; + } + mFlatTable.resize(total, {0, 0}); + size_t offset = 0; + for (int32_t layer{0}; layer < NLayers; ++layer) { + size_t nROFs = this->mLayers[layer].mNROFsTF; + mIndices[layer].setFirstEntry(static_cast(offset)); + mIndices[layer].setEntries(static_cast(nROFs)); + offset += nROFs; + } + } + + // Recalculate lookup table with new vertices + GPUh() void update(const Vertex* vertices, size_t nVertices) + { + size_t offset = 0; + for (int32_t layer{0}; layer < NLayers; ++layer) { + const auto& idx = mIndices[layer]; + size_t nROFs = idx.getEntries(); + for (size_t iROF = 0; iROF < nROFs; ++iROF) { + updateROFMapping(layer, iROF, vertices, nVertices, offset + iROF); + } + offset += nROFs; + } + } + + GPUh() View getView() const + { + View view; + view.mFlatTable = mFlatTable.data(); + view.mIndices = mIndices; + view.mLayers = this->mLayers; + return view; + } + + GPUh() View getDeviceView(const TableEntry* deviceFlatTablePtr, const TableIndex* deviceIndicesPtr, const LayerTiming* deviceLayerTimingPtr) const + { + View view; + view.mFlatTable = deviceFlatTablePtr; + view.mIndices = deviceIndicesPtr; + view.mLayers = deviceLayerTimingPtr; + return view; + } + + private: + // Build the mapping for one layer + GPUh() void buildMapping(int32_t layer, const Vertex* vertices, size_t nVertices, std::vector& table) + { + const auto& layerDef = this->mLayers[layer]; + table.resize(layerDef.mNROFsTF); + size_t vertexSearchStart = 0; + for (int32_t iROF{0}; iROF < layerDef.mNROFsTF; ++iROF) { + int64_t rofLower = o2::gpu::CAMath::Max((int64_t)layerDef.getROFStartInBC(iROF) - (int64_t)layerDef.mROFAddTimeErr, int64_t(0)); + int64_t rofUpper = (int64_t)layerDef.getROFEndInBC(iROF) + layerDef.mROFAddTimeErr; + size_t lastVertex = binarySearchFirst(vertices, nVertices, vertexSearchStart, rofUpper); + size_t firstVertex = vertexSearchStart; + while (firstVertex < lastVertex) { + auto vUpper = (int64_t)vertices[firstVertex].getTimeStamp().upper(); + if (vUpper > rofLower) { + break; + } + ++firstVertex; + } + size_t count = (lastVertex > firstVertex) ? (lastVertex - firstVertex) : 0; + table[iROF] = {static_cast(firstVertex), static_cast(count)}; + vertexSearchStart = firstVertex; + } + } + + // Update a single ROF's vertex mapping + GPUh() void updateROFMapping(int32_t layer, size_t iROF, const Vertex* vertices, size_t nVertices, size_t flatTableIdx) + { + const auto& layerDef = this->mLayers[layer]; + int64_t rofLower = o2::gpu::CAMath::Max((int64_t)layerDef.getROFStartInBC(iROF) - (int64_t)layerDef.mROFAddTimeErr, int64_t(0)); + int64_t rofUpper = (int64_t)layerDef.getROFEndInBC(iROF) + layerDef.mROFAddTimeErr; + size_t lastVertex = binarySearchFirst(vertices, nVertices, 0, rofUpper); + size_t firstVertex = 0; + while (firstVertex < lastVertex) { + int64_t vUpper = (int64_t)vertices[firstVertex].getTimeStamp().getTimeStamp() + + (int64_t)vertices[firstVertex].getTimeStamp().getTimeStampError(); + if (vUpper > rofLower) { + break; + } + ++firstVertex; + } + size_t count = (lastVertex > firstVertex) ? (lastVertex - firstVertex) : 0; + mFlatTable[flatTableIdx].setFirstEntry(static_cast(firstVertex)); + mFlatTable[flatTableIdx].setEntries(static_cast(count)); + } + + // Binary search for first vertex where maxBC >= targetBC + GPUh() size_t binarySearchFirst(const Vertex* vertices, size_t nVertices, size_t searchStart, BCType targetBC) const + { + size_t left = searchStart; + size_t right = nVertices; + while (left < right) { + size_t mid = left + ((right - left) / 2); + int64_t lower = (int64_t)vertices[mid].getTimeStamp().getTimeStamp() - + (int64_t)vertices[mid].getTimeStamp().getTimeStampError(); + if (lower < targetBC) { + left = mid + 1; + } else { + right = mid; + } + } + return left; + } + + // Compress the temporary table into a single flat table + GPUh() void flatten(const std::vector table[NLayers]) + { + // Count total entries + size_t total{0}; + for (int32_t i{0}; i < NLayers; ++i) { + total += table[i].size(); + } + + mFlatTable.reserve(total); + + // Build flat table and indices + for (int32_t i{0}; i < NLayers; ++i) { + mIndices[i].setFirstEntry(static_cast(mFlatTable.size())); + mIndices[i].setEntries(static_cast(table[i].size())); + mFlatTable.insert(mFlatTable.end(), table[i].begin(), table[i].end()); + } + } + + TableIndex mIndices[NLayers]; + std::vector mFlatTable; +}; + +// GPU-friendly view of the ROF mask table +template +struct ROFMaskTableView { + const TableEntry* mFlatMask{nullptr}; + const TableIndex* mLayerROFOffsets{nullptr}; // size NLayers+1 + + GPUhdi() bool isROFEnabled(int32_t layer, int32_t rofId) const noexcept + { + assert(layer >= 0 && layer < NLayers); + return mFlatMask[mLayerROFOffsets[layer] + rofId] != 0u; + } + +#ifndef GPUCA_GPUCODE + GPUh() void printAll() const + { + for (int32_t i = 0; i < NLayers; ++i) { + printLayer(i); + } + } + + GPUh() void printLayer(int32_t layer) const + { + constexpr int w_rof = 10; + constexpr int w_active = 10; + int32_t nROFs = mLayerROFOffsets[layer + 1] - mLayerROFOffsets[layer]; + LOGF(info, "Mask table: Layer %d", layer); + LOGF(info, "%*s | %*s", w_rof, "ROF", w_active, "Enabled"); + LOGF(info, "%.*s-+-%.*s", w_rof, "----------", w_active, "----------"); + for (int32_t i = 0; i < nROFs; ++i) { + LOGF(info, "%*d | %*d", w_rof, i, w_active, (int)isROFEnabled(layer, i)); + } + } + + GPUh() std::string asString(int32_t layer) const + { + int32_t nROFs = mLayerROFOffsets[layer + 1] - mLayerROFOffsets[layer]; + int32_t enabledROFs = 0; + for (int32_t j = 0; j < nROFs; ++j) { + if (isROFEnabled(layer, j)) { + ++enabledROFs; + } + } + return std::format("ROFMask on Layer {} ROFs enabled: {}/{}", layer, enabledROFs, nROFs); + } + + GPUh() void print(int32_t layer) const + { + LOG(info) << asString(layer); + } +#endif +}; + +// Per-ROF per-layer boolean mask (uint8_t for GPU compatibility). +template +class ROFMaskTable : public LayerTimingBase +{ + public: + using T = LayerTimingBase::T; + using BCRange = dataformats::RangeReference; + using TableIndex = uint32_t; + using TableEntry = uint8_t; + using View = ROFMaskTableView; + + ROFMaskTable() = default; + GPUh() explicit ROFMaskTable(const LayerTimingBase& timingBase) : LayerTimingBase(timingBase) { init(); } + + GPUh() void init() + { + int32_t totalROFs = 0; + for (int32_t layer{0}; layer < NLayers; ++layer) { + mLayerROFOffsets[layer] = totalROFs; + totalROFs += this->getLayer(layer).mNROFsTF; + } + mLayerROFOffsets[NLayers] = totalROFs; // sentinel + mFlatMask.resize(totalROFs, 0u); + } + + GPUh() size_t getFlatMaskSize() const noexcept { return mFlatMask.size(); } + + GPUh() void setROFEnabled(int32_t layer, int32_t rofId, uint8_t state = 1) noexcept + { + assert(layer >= 0 && layer < NLayers); + assert(rofId >= 0 && rofId < mLayerROFOffsets[layer + 1] - mLayerROFOffsets[layer]); + mFlatMask[mLayerROFOffsets[layer] + rofId] = state; + } + + GPUh() void setROFsEnabled(int32_t layer, int32_t firstRof, int32_t nRofs, uint8_t state = 1) noexcept + { + assert(layer >= 0 && layer < NLayers); + assert(firstRof >= 0); + assert(firstRof + nRofs <= mLayerROFOffsets[layer + 1] - mLayerROFOffsets[layer]); + std::memset(mFlatMask.data() + mLayerROFOffsets[layer] + firstRof, state, nRofs); + } + + // Enable all ROFs in all layers that are time-compatible with the given BC range + GPUh() void selectROF(const BCRange& t) + { + const int32_t bcStart = t.getFirstEntry(); + const int32_t bcEnd = t.getEntriesBound(); + for (int32_t layer{0}; layer < NLayers; ++layer) { + const auto& lay = this->getLayer(layer); + const int32_t offset = mLayerROFOffsets[layer]; + for (int32_t rofId{0}; rofId < lay.mNROFsTF; ++rofId) { + if (static_cast(lay.getROFStartInBC(rofId)) < bcEnd && + static_cast(lay.getROFEndInBC(rofId)) > bcStart) { + mFlatMask[offset + rofId] = 1u; + } + } + } + } + + // Reset mask to 0, then enable all ROFs compatible with any of the given BC ranges + GPUh() void selectROFs(const std::vector& ts) + { + resetMask(); + for (const auto& t : ts) { + selectROF(t); + } + } + + GPUh() void resetMask(uint8_t s = 0u) + { + std::memset(mFlatMask.data(), s, mFlatMask.size()); + } + + GPUh() void invertMask() + { + std::ranges::transform(mFlatMask, mFlatMask.begin(), [](uint8_t x) { return 1 - x; }); + } + + GPUh() void swap(ROFMaskTable& other) noexcept + { + std::swap(mFlatMask, other.mFlatMask); + std::swap(mLayerROFOffsets, other.mLayerROFOffsets); + } + + GPUh() View getView() const + { + View view; + view.mFlatMask = mFlatMask.data(); + view.mLayerROFOffsets = mLayerROFOffsets; + return view; + } + + GPUh() View getDeviceView(const TableEntry* deviceFlatMaskPtr, const TableIndex* deviceOffsetPtr) const + { + View view; + view.mFlatMask = deviceFlatMaskPtr; + view.mLayerROFOffsets = deviceOffsetPtr; + return view; + } + + private: + TableIndex mLayerROFOffsets[NLayers + 1] = {0}; + std::vector mFlatMask; +}; + +} // namespace o2::its + +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ROframe.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ROframe.h deleted file mode 100644 index d35e5bc545904..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ROframe.h +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file ROframe.h -/// \brief -/// - -#ifndef TRACKINGITSU_INCLUDE_ROFRAME_H_ -#define TRACKINGITSU_INCLUDE_ROFRAME_H_ - -#include -#include -#include -#include -#include - -#include "ITStracking/Cluster.h" -#include "ITStracking/Constants.h" - -#include "ReconstructionDataFormats/Vertex.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" - -namespace o2 -{ -namespace its -{ - -using Vertex = o2::dataformats::Vertex>; - -class ROframe final -{ - public: - ROframe(int ROframeId, int nLayers); - int getROFrameId() const; - const float3& getPrimaryVertex(const int) const; - int getPrimaryVerticesNum() const; - void addPrimaryVertex(const float, const float, const float); - void addPrimaryVertices(std::vector vertices); - void addPrimaryReconstructedVertex(const float, const float, const float); - void printPrimaryVertices() const; - int getTotalClusters() const; - bool empty() const; - - const auto& getClusters() const { return mClusters; } - const std::vector& getClustersOnLayer(int layerId) const; - const std::vector& getTrackingFrameInfoOnLayer(int layerId) const; - const auto& getTrackingFrameInfo() const { return mTrackingFrameInfo; } - - const TrackingFrameInfo& getClusterTrackingFrameInfo(int layerId, const Cluster& cl) const; - const MCCompLabel& getClusterFirstLabel(int layerId, const Cluster& cl) const; - const MCCompLabel& getClusterFirstLabel(int layerId, const int clId) const; - const gsl::span getClusterLabels(int layerId, const int clId) const; - const gsl::span getClusterLabels(int layerId, const Cluster& cl) const; - int getClusterExternalIndex(int layerId, const int clId) const; - std::vector getTracksId(const int layerId, const std::vector& cl); - - template - void addClusterToLayer(int layer, T&&... args); - template - void addTrackingFrameInfoToLayer(int layer, T&&... args); - void setMClabelsContainer(const dataformats::MCTruthContainer* ptr); - void addClusterExternalIndexToLayer(int layer, const int idx); - bool hasMCinformation() const; - - void clear(); - - private: - const int mROframeId; - const o2::dataformats::MCTruthContainer* mMClabels = nullptr; - std::vector mPrimaryVertices; - std::vector> mClusters; - std::vector> mTrackingFrameInfo; - std::vector> mClusterExternalIndices; -}; - -inline int ROframe::getROFrameId() const { return mROframeId; } - -inline const float3& ROframe::getPrimaryVertex(const int vertexIndex) const { return mPrimaryVertices[vertexIndex]; } - -inline int ROframe::getPrimaryVerticesNum() const { return mPrimaryVertices.size(); } - -inline bool ROframe::empty() const { return getTotalClusters() == 0; } - -inline const std::vector& ROframe::getClustersOnLayer(int layerId) const -{ - return mClusters[layerId]; -} - -inline const std::vector& ROframe::getTrackingFrameInfoOnLayer(int layerId) const -{ - return mTrackingFrameInfo[layerId]; -} - -inline const TrackingFrameInfo& ROframe::getClusterTrackingFrameInfo(int layerId, const Cluster& cl) const -{ - return mTrackingFrameInfo[layerId][cl.clusterId]; -} - -inline const MCCompLabel& ROframe::getClusterFirstLabel(int layerId, const Cluster& cl) const -{ - return getClusterFirstLabel(layerId, cl.clusterId); -} - -inline const MCCompLabel& ROframe::getClusterFirstLabel(int layerId, const int clId) const -{ - return *(mMClabels->getLabels(getClusterExternalIndex(layerId, clId)).begin()); -} - -inline const gsl::span ROframe::getClusterLabels(int layerId, const int clId) const -{ - return mMClabels->getLabels(getClusterExternalIndex(layerId, clId)); -} - -inline const gsl::span ROframe::getClusterLabels(int layerId, const Cluster& cl) const -{ - return getClusterLabels(layerId, cl.clusterId); -} - -inline int ROframe::getClusterExternalIndex(int layerId, const int clId) const -{ - return mClusterExternalIndices[layerId][clId]; -} - -inline std::vector ROframe::getTracksId(const int layerId, const std::vector& cl) -{ - std::vector tracksId; - for (auto& cluster : cl) { - tracksId.push_back(getClusterFirstLabel(layerId, cluster).isNoise() ? -1 : getClusterFirstLabel(layerId, cluster).getTrackID()); - } - return tracksId; -} - -template -void ROframe::addClusterToLayer(int layer, T&&... values) -{ - mClusters[layer].emplace_back(std::forward(values)...); -} - -template -void ROframe::addTrackingFrameInfoToLayer(int layer, T&&... values) -{ - mTrackingFrameInfo[layer].emplace_back(std::forward(values)...); -} - -inline void ROframe::setMClabelsContainer(const dataformats::MCTruthContainer* ptr) -{ - mMClabels = ptr; -} - -inline void ROframe::addClusterExternalIndexToLayer(int layer, const int idx) -{ - mClusterExternalIndices[layer].push_back(idx); -} - -inline void ROframe::clear() -{ - for (unsigned int iL = 0; iL < mClusters.size(); ++iL) { - mClusters[iL].clear(); - mTrackingFrameInfo[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; - return mMClabels; -} - -} // namespace its -} // namespace o2 - -#endif /* TRACKINGITSU_INCLUDE_ROFRAME_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Road.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Road.h deleted file mode 100644 index bc3786ba612b9..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Road.h +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file Road.h -/// \brief -/// - -#ifndef TRACKINGCA_INCLUDE_ROAD_H -#define TRACKINGCA_INCLUDE_ROAD_H - -#ifndef GPUCA_GPUCODE_DEVICE -#include -#endif - -#include "ITStracking/Constants.h" -#include "GPUCommonDef.h" - -namespace o2 -{ -namespace its -{ - -template -class Road final -{ - public: - GPUhd() Road() : mCellIds{}, mRoadSize{}, mIsFakeRoad{} { resetRoad(); } - GPUhd() Road(int cellLayer, int cellId) : Road() { addCell(cellLayer, cellId); } - - GPUhd() int getRoadSize() const; - int getLabel() const; - void setLabel(const int); - GPUhd() bool isFakeRoad() const; - void setFakeRoad(const bool); - GPUhd() int& operator[](const int&); - GPUhd() int operator[](const int&) const; - - GPUhd() void resetRoad() - { - for (int i = 0; i < maxRoadSize; i++) { - mCellIds[i] = constants::its::UnusedIndex; - } - mRoadSize = 0; - } - - GPUhd() void addCell(int cellLayer, int cellId) - { - if (mCellIds[cellLayer] == constants::its::UnusedIndex) { - ++mRoadSize; - } - - mCellIds[cellLayer] = cellId; - } - - private: - int mCellIds[maxRoadSize]; - // int mLabel; - unsigned char mRoadSize; - bool mIsFakeRoad; -}; - -template -GPUhdi() int Road::getRoadSize() const -{ - return mRoadSize; -} - -template -GPUhdi() int& Road::operator[](const int& i) -{ - return mCellIds[i]; -} - -template -GPUhdi() int Road::operator[](const int& i) const -{ - return mCellIds[i]; -} - -template -GPUhdi() bool Road::isFakeRoad() const -{ - return mIsFakeRoad; -} - -template -inline void Road::setFakeRoad(const bool isFakeRoad) -{ - mIsFakeRoad = isFakeRoad; -} -} // namespace its -} // namespace o2 - -#endif \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Smoother.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Smoother.h deleted file mode 100644 index 2dcd521797837..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Smoother.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -/// \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" - -namespace o2 -{ -namespace its -{ - -template -class Smoother -{ - public: - Smoother(TrackITSExt& track, size_t 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& cls, - const std::array& clCov); - bool smoothTrack(); - - private: - size_t 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 -}; -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h index 46c4a8e19fa47..3fef2dc640cbc 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h @@ -16,30 +16,26 @@ #include #include #include +#include #include -#include #include -#include -#include -#include #include "DataFormatsITS/TrackITS.h" +#include "DataFormatsITS/Vertex.h" #include "ITStracking/Cell.h" #include "ITStracking/Cluster.h" #include "ITStracking/Configuration.h" -#include "ITStracking/Constants.h" #include "ITStracking/ClusterLines.h" -#include "ITStracking/Definitions.h" -#include "ITStracking/Road.h" #include "ITStracking/Tracklet.h" #include "ITStracking/IndexTableUtils.h" #include "ITStracking/ExternalAllocator.h" - +#include "ITStracking/BoundedAllocator.h" +#include "ITStracking/ROFLookupTables.h" +#include "ITStracking/TrackingTopology.h" #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" -#include "ReconstructionDataFormats/Vertex.h" #include "DetectorsBase/Propagator.h" namespace o2 @@ -59,143 +55,182 @@ class ROFRecord; namespace its { -using Vertex = o2::dataformats::Vertex>; - -class TimeFrame -{ - public: - friend class TimeFrameGPU; - TimeFrame(int nLayers = 7); - const Vertex& getPrimaryVertex(const int) const; - gsl::span getPrimaryVertices(int rofId) const; - gsl::span getPrimaryVertices(int romin, int romax) const; - gsl::span> getPrimaryVerticesMCRecInfo(const int rofId) const; - gsl::span> getPrimaryVerticesXAlpha(int rofId) const; - void fillPrimaryVerticesXandAlpha(); - int getPrimaryVerticesNum(int rofId = -1) const; - void addPrimaryVertices(const std::vector& vertices); - void addPrimaryVerticesLabels(std::vector>& labels); - void addPrimaryVertices(const std::vector& vertices, const int rofId, const int iteration); - void addPrimaryVertices(const gsl::span& vertices, const int rofId, const int iteration); - void addPrimaryVerticesInROF(const std::vector& vertices, const int rofId, const int iteration); - void addPrimaryVerticesLabelsInROF(const std::vector>& labels, const int rofId); - void removePrimaryVerticesInROf(const int rofId); - int loadROFrameData(const o2::itsmft::ROFRecord& rof, gsl::span clusters, - const dataformats::MCTruthContainer* mcLabels = nullptr); - - int loadROFrameData(gsl::span rofs, - gsl::span clusters, - gsl::span::iterator& pattIt, - const itsmft::TopologyDictionary* dict, - const dataformats::MCTruthContainer* mcLabels = nullptr); +namespace gpu +{ +template +class TimeFrameGPU; +} + +template +struct TimeFrame { + using IndexTableUtilsN = IndexTableUtils; + using ROFOverlapTableN = ROFOverlapTable; + using ROFVertexLookupTableN = ROFVertexLookupTable; + using ROFMaskTableN = ROFMaskTable; + using TrackingTopologyN = TrackingTopology; + using TrackSeedN = TrackSeed; + friend class gpu::TimeFrameGPU; + + TimeFrame() = default; + virtual ~TimeFrame() = default; + + const Vertex& getPrimaryVertex(const int ivtx) const { return mPrimaryVertices[ivtx]; } + auto& getPrimaryVertices() { return mPrimaryVertices; }; + auto getPrimaryVerticesNum() { return mPrimaryVertices.size(); }; + const auto& getPrimaryVertices() const { return mPrimaryVertices; }; + auto& getPrimaryVerticesLabels() { return mPrimaryVerticesLabels; }; + gsl::span getPrimaryVertices(int layer, int rofId) const; + void addPrimaryVertex(const Vertex& vertex); + void addPrimaryVertexLabel(const VertexLabel& label) { mPrimaryVerticesLabels.push_back(label); } + + // read-in data + void loadROFrameData(gsl::span rofs, + gsl::span clusters, + gsl::span::iterator& pattIt, + const itsmft::TopologyDictionary* dict, + int layer, + const dataformats::MCTruthContainer* mcLabels = nullptr); + void resetROFrameData(int iLayer); + void prepareROFrameData(gsl::span clusters, int layer); int getTotalClusters() const; - std::vector& getTotVertIteration() { return mTotVertPerIteration; } - bool empty() const; - bool isGPU() const { return mIsGPU; } - int getSortedIndex(int rofId, int layer, int i) const; - int getSortedStartIndex(const int, const int) const; - int getNrof() const; + bool empty() const { return getTotalClusters() == 0; } + int getSortedIndex(int rofId, int layer, int idx) const { return mROFramesClusters[layer][rofId] + idx; } + int getSortedStartIndex(const int rofId, const int layer) const { return mROFramesClusters[layer][rofId]; } + int getNrof(int layer) const { return mROFramesClusters[layer].size() - 1; } void resetBeamXY(const float x, const float y, const float w = 0); void setBeamPosition(const float x, const float y, const float s2, const float base = 50.f, const float systematic = 0.f) { isBeamPositionOverridden = true; - resetBeamXY(x, y, s2 / o2::gpu::CAMath::Sqrt(base * base + systematic)); + resetBeamXY(x, y, s2 / o2::gpu::CAMath::Sqrt((base * base) + systematic)); } - float getBeamX() const; - float getBeamY() const; - std::vector& getMinRs() { return mMinR; } - std::vector& getMaxRs() { return mMaxR; } + float getBeamX() const { return mBeamPos[0]; } + float getBeamY() const { return mBeamPos[1]; } + std::array& getBeamXY() { return mBeamPos; } + + auto& getMinRs() { return mMinR; } + auto& getMaxRs() { return mMaxR; } float getMinR(int layer) const { return mMinR[layer]; } float getMaxR(int layer) const { return mMaxR[layer]; } - float getMSangle(int layer) const { return mMSangles[layer]; } - std::vector& getMSangles() { return mMSangles; } - float getPhiCut(int layer) const { return mPhiCuts[layer]; } - std::vector& getPhiCuts() { return mPhiCuts; } + float getTransitionPhiCut(int transitionId) const { return mTransitionPhiCuts[transitionId]; } + float getTransitionMSAngle(int transitionId) const { return mTransitionMSAngles[transitionId]; } + auto& getTransitionPhiCuts() { return mTransitionPhiCuts; } + auto& getTransitionMSAngles() { return mTransitionMSAngles; } float getPositionResolution(int layer) const { return mPositionResolution[layer]; } - std::vector& getPositionResolutions() { return mPositionResolution; } + auto& getPositionResolutions() { return mPositionResolution; } gsl::span getClustersOnLayer(int rofId, int layerId); gsl::span getClustersOnLayer(int rofId, int layerId) const; gsl::span getClustersPerROFrange(int rofMin, int range, int layerId) const; gsl::span getUnsortedClustersOnLayer(int rofId, int layerId) const; - gsl::span getUsedClustersROF(int rofId, int layerId); - gsl::span getUsedClustersROF(int rofId, int layerId) const; + gsl::span getUsedClustersROF(int rofId, int layerId); + gsl::span getUsedClustersROF(int rofId, int layerId) const; gsl::span getROFramesClustersPerROFrange(int rofMin, int range, int layerId) const; gsl::span getROFrameClusters(int layerId) const; gsl::span getNClustersROFrange(int rofMin, int range, int layerId) const; - gsl::span getIndexTablePerROFrange(int rofMin, int range, int layerId) const; gsl::span getIndexTable(int rofId, int layerId); - std::vector& getIndexTableWhole(int layerId) { return mIndexTables[layerId]; } - const std::vector& getTrackingFrameInfoOnLayer(int layerId) const; - - const TrackingFrameInfo& getClusterTrackingFrameInfo(int layerId, const Cluster& cl) const; - const gsl::span getClusterLabels(int layerId, const Cluster& cl) const; - const gsl::span getClusterLabels(int layerId, const int clId) const; - int getClusterExternalIndex(int layerId, const int clId) const; - int getClusterSize(int clusterId) const; - void setClusterSize(const std::vector& v) { mClusterSize = v; }; - - std::vector& getTrackletsLabel(int layer) { return mTrackletLabels[layer]; } - std::vector& getCellsLabel(int layer) { return mCellLabels[layer]; } - - bool hasMCinformation() const; - void initialise(const int iteration, const TrackingParameters& trkParam, const int maxLayers = 7, bool resetVertices = true); - void resetRofPV() + const auto& getTrackingFrameInfoOnLayer(int layerId) const { return mTrackingFrameInfo[layerId]; } + + // navigation tables + const auto& getIndexTableUtils() const { return mIndexTableUtils; } + const auto& getROFOverlapTable() const { return mROFOverlapTable; } + const auto& getROFOverlapTableView() const { return mROFOverlapTableView; } + const auto& getTrackerTopologies() const { return mTrackerTopologies; } + const auto& getTrackingTopologyView() const { return mTrackingTopologyView; } + void setROFOverlapTable(ROFOverlapTableN table) + { + mROFOverlapTable = std::move(table); + mROFOverlapTableView = mROFOverlapTable.getView(); + } + const auto& getROFVertexLookupTable() const { return mROFVertexLookupTable; } + const auto& getROFVertexLookupTableView() const { return mROFVertexLookupTableView; } + void setROFVertexLookupTable(ROFVertexLookupTableN table) + { + mROFVertexLookupTable = std::move(table); + mROFVertexLookupTableView = mROFVertexLookupTable.getView(); + } + void updateROFVertexLookupTable() { mROFVertexLookupTable.update(mPrimaryVertices.data(), mPrimaryVertices.size()); } + void setMultiplicityCutMask(ROFMaskTableN cutMask) + { + mMultiplicityCutMask = std::move(cutMask); + mROFMaskView = mROFMask->getView(); + } + void useMultiplictyMask() noexcept + { + mROFMask = &mMultiplicityCutMask; + mROFMaskView = mROFMask->getView(); + } + void setUPCCutMask(ROFMaskTableN cutMask) { mUPCCutMask = std::move(cutMask); } + void useUPCMask() noexcept { - deepVectorClear(mPrimaryVertices); - mROFramesPV.resize(1, 0); - mTotVertPerIteration.resize(1); - }; + mROFMask = &mUPCCutMask; + mROFMaskView = mROFMask->getView(); + } + const auto& getROFMaskView() const { return mROFMaskView; } - bool isClusterUsed(int layer, int clusterId) const; - void markUsedCluster(int layer, int clusterId); + const TrackingFrameInfo& getClusterTrackingFrameInfo(int layerId, const Cluster& cl) const; + gsl::span getClusterLabels(int layerId, const Cluster& cl) const { return getClusterLabels(layerId, cl.clusterId); } + gsl::span getClusterLabels(int layerId, const int clId) const { return mClusterLabels[((mIsStaggered) ? layerId : 0)]->getLabels(mClusterExternalIndices[layerId][clId]); } + int getClusterExternalIndex(int layerId, const int clId) const { return mClusterExternalIndices[layerId][clId]; } + int getClusterSize(int layer, int clusterId) const { return mClusterSize[layer][clusterId]; } + void setClusterSize(int layer, bounded_vector& v) { mClusterSize[layer] = std::move(v); } + + auto& getTrackletsLabel(int layer) { return mTrackletLabels[layer]; } + auto& getCellsLabel(int layer) { return mCellLabels[layer]; } + + bool hasMCinformation() const { return mClusterLabels[0] != nullptr; } + void initVertexingTopology(const TrackingParameters& trkParam); + void initDefaultTrackingTopology(const TrackingParameters& trkParam, const int maxLayers = NLayers); + void initTrackerTopologies(gsl::span trkParams, const int maxLayers = NLayers); + void initialise(const TrackingParameters& trkParam, const int maxLayers = NLayers, const int iteration = constants::UnusedIndex); + + bool isClusterUsed(int layer, int clusterId) const { return mUsedClusters[layer][clusterId]; } + void markUsedCluster(int layer, int clusterId) { mUsedClusters[layer][clusterId] = true; } gsl::span getUsedClusters(const int layer); - std::vector>& getTracklets(); - std::vector>& getTrackletsLookupTable(); + auto& getTracklets() { return mTracklets; } + auto& getTrackletsLookupTable() { return mTrackletsLookupTable; } - std::vector>& getClusters(); - std::vector>& getUnsortedClusters(); + auto& getClusters() { return mClusters; } + auto& getUnsortedClusters() { return mUnsortedClusters; } int getClusterROF(int iLayer, int iCluster); - std::vector>& getCells(); - - std::vector>& getCellsLookupTable(); - std::vector>& getCellsNeighbours(); - std::vector>& getCellsNeighboursLUT(); - std::vector>& getRoads(); - std::vector& getTracks(int rofId) { return mTracks[rofId]; } - std::vector& getTracksLabel(const int rofId) { return mTracksLabel[rofId]; } - std::vector& getLinesLabel(const int rofId) { return mLinesLabels[rofId]; } - std::vector>& getVerticesMCRecInfo() { return mVerticesMCRecInfo; } - - int getNumberOfClusters() const; - int getNumberOfCells() const; - int getNumberOfTracklets() const; - int getNumberOfNeighbours() const; + auto& getCells() { return mCells; } + + auto& getCellsLookupTable() { return mCellsLookupTable; } + auto& getCellsNeighbours() { return mCellsNeighbours; } + auto& getCellsNeighboursTopology() { return mCellsNeighboursTopology; } + auto& getCellsNeighboursLUT() { return mCellsNeighboursLUT; } + auto& getTracks() { return mTracks; } + auto& getTracksLabel() { return mTracksLabel; } + auto& getLinesLabel(const int rofId) { return mLinesLabels[rofId]; } + + size_t getNumberOfClusters() const; + virtual size_t getNumberOfCells() const; + virtual size_t getNumberOfTracklets() const; + virtual size_t getNumberOfNeighbours() const; size_t getNumberOfTracks() const; size_t getNumberOfUsedClusters() const; - auto getNumberOfExtendedTracks() const { return mNExtendedTracks; } - auto getNumberOfUsedExtendedClusters() const { return mNExtendedUsedClusters; } + /// memory management + void setMemoryPool(std::shared_ptr pool); + auto& getMemoryPool() const noexcept { return mMemoryPool; } bool checkMemory(unsigned long max) { return getArtefactsMemory() < max; } - unsigned long getArtefactsMemory(); - int getROFCutClusterMult() const { return mCutClusterMult; }; - int getROFCutVertexMult() const { return mCutVertexMult; }; - int getROFCutAllMult() const { return mCutClusterMult + mCutVertexMult; } + unsigned long getArtefactsMemory() const; + void printArtefactsMemory() const; + + /// staggering + void setIsStaggered(bool b) noexcept { mIsStaggered = b; } // Vertexer void computeTrackletsPerROFScans(); void computeTracletsPerClusterScans(); - int& getNTrackletsROF(int rofId, int combId); - std::vector& getLines(int rofId); - int getNLinesTotal() const - { - return std::accumulate(mLines.begin(), mLines.end(), 0, [](int sum, const auto& l) { return sum + l.size(); }); - } - std::vector& getTrackletClusters(int rofId); + int& getNTrackletsROF(int rofId, int combId) { return mNTrackletsPerROF[combId][rofId]; } + auto& getLines(int rofId) { return mLines[rofId]; } + int getNLinesTotal() const noexcept { return mTotalLines; } + void setNLinesTotal(uint32_t a) noexcept { mTotalLines = a; } + auto& getTrackletClusters(int rofId) { return mTrackletClusters[rofId]; } gsl::span getFoundTracklets(int rofId, int combId) const; gsl::span getFoundTracklets(int rofId, int combId); gsl::span getLabelsFoundTracklets(int rofId, int combId) const; @@ -203,551 +238,372 @@ class TimeFrame gsl::span getExclusiveNTrackletsCluster(int rofId, int combId); uint32_t getTotalTrackletsTF(const int iLayer) { return mTotalTracklets[iLayer]; } int getTotalClustersPerROFrange(int rofMin, int range, int layerId) const; - std::array& getBeamXY() { return mBeamPos; } - unsigned int& getNoVertexROF() { return mNoVertexROF; } - void insertPastVertex(const Vertex& vertex, const int refROFId); // \Vertexer - 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 setMultiplicityCutMask(const std::vector& cutMask) { mMultiplicityCutMask = cutMask; } - void setROFMask(const std::vector& rofMask) { mROFMask = rofMask; } - void swapMasks() { mMultiplicityCutMask.swap(mROFMask); } - int hasBogusClusters() const { return std::accumulate(mBogusClusters.begin(), mBogusClusters.end(), 0); } void setBz(float bz) { mBz = bz; } float getBz() const { return mBz; } - void setExternalAllocator(ExternalAllocator* allocator) - { - if (mIsGPU) { - LOGP(debug, "Setting timeFrame allocator to external"); - mAllocator = allocator; - mExtAllocator = true; // to be removed - } else { - LOGP(debug, "External allocator is currently only supported for GPU"); - } - } + /// State if memory will be externally managed by the GPU framework + ExternalAllocator* mExternalAllocator{nullptr}; + std::shared_ptr mExtMemoryPool; // host memory pool managed by the framework + auto getFrameworkAllocator() { return mExternalAllocator; }; + void setFrameworkAllocator(ExternalAllocator* ext); + bool hasFrameworkAllocator() const noexcept { return mExternalAllocator != nullptr; } + std::pmr::memory_resource* getMaybeFrameworkHostResource(bool forceHost = false) { return (hasFrameworkAllocator() && !forceHost) ? mExtMemoryPool.get() : mMemoryPool.get(); } - virtual void setDevicePropagator(const o2::base::PropagatorImpl*) - { - return; - }; + // Propagator const o2::base::PropagatorImpl* getDevicePropagator() const { return mPropagatorDevice; } + virtual void setDevicePropagator(const o2::base::PropagatorImpl* /*unused*/) {}; template void addClusterToLayer(int layer, T&&... args); template void addTrackingFrameInfoToLayer(int layer, T&&... args); - void addClusterExternalIndexToLayer(int layer, const int idx); - - void resizeVectors(int nLayers); - - void setExtAllocator(bool ext) { mExtAllocator = ext; } - bool getExtAllocator() const { return mExtAllocator; } - - /// Debug and printing - void checkTrackletLUTs(); - void printROFoffsets(); - void printNClsPerROF(); - void printVertices(); - void printTrackletLUTonLayer(int i); - void printCellLUTonLayer(int i); - void printTrackletLUTs(); - void printCellLUTs(); - void printSliceInfo(const int, const int); - - IndexTableUtils mIndexTableUtils; - - bool mIsGPU = false; - - std::vector> mClusters; - std::vector> mTrackingFrameInfo; - std::vector> mClusterExternalIndices; - std::vector> mROFramesClusters; - const dataformats::MCTruthContainer* mClusterLabels = nullptr; - std::array, 2> mNTrackletsPerCluster; - std::array, 2> mNTrackletsPerClusterSum; - std::vector> mNClustersPerROF; - std::vector> mIndexTables; - std::vector> mTrackletsLookupTable; - std::vector> mUsedClusters; - int mNrof = 0; - int mNExtendedTracks{0}; - int mNExtendedUsedClusters{0}; - std::vector mROFramesPV = {0}; - std::vector mPrimaryVertices; - - // State if memory will be externally managed. - bool mExtAllocator = false; - ExternalAllocator* mAllocator = nullptr; - std::vector> mUnsortedClusters; - std::vector> mTracklets; - std::vector> mCells; - std::vector> mCellSeeds; - std::vector> mCellSeedsChi2; - std::vector> mRoads; - std::vector> mTracks; - std::vector> mCellsNeighbours; - std::vector> mCellsLookupTable; - std::vector mMultiplicityCutMask; + void addClusterExternalIndexToLayer(int layer, const int idx) { mClusterExternalIndices[layer].push_back(idx); } + + std::array, NLayers> mClusters; + std::array, NLayers> mTrackingFrameInfo; + std::array, NLayers> mClusterExternalIndices; + std::array, NLayers> mROFramesClusters; + std::array*, NLayers> mClusterLabels{nullptr}; + std::array, 2> mNTrackletsPerCluster; + std::array, 2> mNTrackletsPerClusterSum; + std::array, NLayers> mNClustersPerROF; + std::array, NLayers> mIndexTables; + std::vector> mTrackletsLookupTable; + std::array, NLayers> mUsedClusters; + + std::array, NLayers> mUnsortedClusters; + std::vector> mTracklets; + std::vector> mCells; + bounded_vector mTracks; + bounded_vector mTracksLabel; + std::vector> mCellsNeighbours; + std::vector> mCellsNeighboursTopology; + std::vector> mCellsLookupTable; const o2::base::PropagatorImpl* mPropagatorDevice = nullptr; // Needed only for GPU - void dropTracks() - { - for (auto& v : mTracks) { - deepVectorClear(v); - } - } - protected: - template - void deepVectorClear(std::vector& vec) - { - std::vector().swap(vec); - } + virtual void wipe(); + + // interface + virtual bool isGPU() const noexcept { return false; } + virtual const char* getName() const noexcept { return "CPU"; } - private: - void prepareClusters(const TrackingParameters& trkParam, const int maxLayers); + protected: + void prepareClusters(const TrackingParameters& trkParam, const int maxLayers = NLayers); float mBz = 5.; unsigned int mNTotalLowPtVertices = 0; int mBeamPosWeight = 0; std::array mBeamPos = {0.f, 0.f}; bool isBeamPositionOverridden = false; - std::vector mMinR; - std::vector mMaxR; - std::vector mMSangles; - std::vector mPhiCuts; - std::vector mPositionResolution; - std::vector mClusterSize; - - std::vector mROFMask; - std::vector> mPValphaX; /// PV x and alpha for track propagation - std::vector> mTrackletLabels; - std::vector> mCellLabels; - std::vector> mCellsNeighboursLUT; - std::vector> mTracksLabel; - std::vector mBogusClusters; /// keep track of clusters with wild coordinates - - std::vector> mRoadLabels; - int mCutClusterMult; - int mCutVertexMult; + std::array mMinR; + std::array mMaxR; + bounded_vector mTransitionPhiCuts; + bounded_vector mTransitionMSAngles; + bounded_vector mPositionResolution; + std::array, NLayers> mClusterSize; + + bounded_vector> mPValphaX; /// PV x and alpha for track propagation + std::vector> mTrackletLabels; + std::vector> mCellLabels; + std::vector> mCellsNeighboursLUT; + bounded_vector mBogusClusters; /// keep track of clusters with wild coordinates // Vertexer - std::vector> mNTrackletsPerROF; - std::vector> mLines; - std::vector> mTrackletClusters; - std::vector> mTrackletsIndexROF; - std::vector> mLinesLabels; - std::vector> mVerticesMCRecInfo; + bounded_vector mPrimaryVertices; + bounded_vector mPrimaryVerticesLabels; + std::vector> mNTrackletsPerROF; + std::vector> mLines; + std::vector> mTrackletClusters; + std::array, 2> mTrackletsIndexROF; + std::vector> mLinesLabels; std::array mTotalTracklets = {0, 0}; - unsigned int mNoVertexROF = 0; - std::vector mTotVertPerIteration; + uint32_t mTotalLines = 0; // \Vertexer -}; - -inline const Vertex& TimeFrame::getPrimaryVertex(const int vertexIndex) const { return mPrimaryVertices[vertexIndex]; } - -inline gsl::span TimeFrame::getPrimaryVertices(int rofId) const -{ - const int start = mROFramesPV[rofId]; - const int stop_idx = rofId >= mNrof - 1 ? mNrof : rofId + 1; - int delta = mMultiplicityCutMask[rofId] ? mROFramesPV[stop_idx] - start : 0; // return empty span if Rof is excluded - return {&mPrimaryVertices[start], static_cast::size_type>(delta)}; -} - -inline gsl::span> TimeFrame::getPrimaryVerticesMCRecInfo(const int rofId) const -{ - const int start = mROFramesPV[rofId]; - const int stop_idx = rofId >= mNrof - 1 ? mNrof : rofId + 1; - int delta = mMultiplicityCutMask[rofId] ? mROFramesPV[stop_idx] - start : 0; // return empty span if Rof is excluded - return {&(mVerticesMCRecInfo[start]), static_cast>::size_type>(delta)}; -} -inline gsl::span TimeFrame::getPrimaryVertices(int romin, int romax) const -{ - return {&mPrimaryVertices[mROFramesPV[romin]], static_cast::size_type>(mROFramesPV[romax + 1] - mROFramesPV[romin])}; -} - -inline gsl::span> TimeFrame::getPrimaryVerticesXAlpha(int rofId) const -{ - const int start = mROFramesPV[rofId]; - const int stop_idx = rofId >= mNrof - 1 ? mNrof : rofId + 1; - int delta = mMultiplicityCutMask[rofId] ? mROFramesPV[stop_idx] - start : 0; // return empty span if Rof is excluded - return {&(mPValphaX[start]), static_cast>::size_type>(delta)}; -} + // lookup tables + IndexTableUtilsN mIndexTableUtils; + ROFOverlapTableN mROFOverlapTable; + ROFOverlapTableN::View mROFOverlapTableView; + TrackingTopologyN mVertexingTopology; + TrackingTopologyN mDefaultTrackingTopology; + std::vector mTrackerTopologies; + typename TrackingTopologyN::View mTrackingTopologyView; + ROFVertexLookupTableN mROFVertexLookupTable; + ROFVertexLookupTableN::View mROFVertexLookupTableView; + ROFMaskTableN mMultiplicityCutMask; + ROFMaskTableN mUPCCutMask; + ROFMaskTableN* mROFMask = &mMultiplicityCutMask; + ROFMaskTableN::View mROFMaskView; + + bool mIsStaggered{false}; + + std::shared_ptr mMemoryPool; +}; -inline int TimeFrame::getPrimaryVerticesNum(int rofId) const +template +gsl::span TimeFrame::getPrimaryVertices(int layer, int rofId) const { - return rofId < 0 ? mPrimaryVertices.size() : mROFramesPV[rofId + 1] - mROFramesPV[rofId]; + if (rofId < 0 || rofId >= getNrof(layer)) { + return {}; + } + const auto& entry = mROFVertexLookupTableView.getVertices(layer, rofId); + return {&mPrimaryVertices[entry.getFirstEntry()], static_cast::size_type>(entry.getEntries())}; } -inline bool TimeFrame::empty() const { return getTotalClusters() == 0; } - -inline int TimeFrame::getSortedIndex(int rofId, int layer, int index) const { return mROFramesClusters[layer][rofId] + index; } - -inline int TimeFrame::getSortedStartIndex(const int rofId, const int layer) const { return mROFramesClusters[layer][rofId]; } - -inline int TimeFrame::getNrof() const { return mNrof; } - -inline void TimeFrame::resetBeamXY(const float x, const float y, const float w) +template +inline void TimeFrame::resetBeamXY(const float x, const float y, const float w) { mBeamPos[0] = x; mBeamPos[1] = y; mBeamPosWeight = w; } -inline float TimeFrame::getBeamX() const { return mBeamPos[0]; } - -inline float TimeFrame::getBeamY() const { return mBeamPos[1]; } - -inline gsl::span TimeFrame::getROFrameClusters(int layerId) const +template +inline gsl::span TimeFrame::getROFrameClusters(int layerId) const { return {&mROFramesClusters[layerId][0], static_cast::size_type>(mROFramesClusters[layerId].size())}; } -inline gsl::span TimeFrame::getClustersOnLayer(int rofId, int layerId) +template +inline gsl::span TimeFrame::getClustersOnLayer(int rofId, int layerId) { - if (rofId < 0 || rofId >= mNrof) { - return gsl::span(); + if (rofId < 0 || rofId >= getNrof(layerId)) { + return {}; } int startIdx{mROFramesClusters[layerId][rofId]}; return {&mClusters[layerId][startIdx], static_cast::size_type>(mROFramesClusters[layerId][rofId + 1] - startIdx)}; } -inline gsl::span TimeFrame::getClustersOnLayer(int rofId, int layerId) const +template +inline gsl::span TimeFrame::getClustersOnLayer(int rofId, int layerId) const { - if (rofId < 0 || rofId >= mNrof) { - return gsl::span(); + if (rofId < 0 || rofId >= getNrof(layerId)) { + return {}; } int startIdx{mROFramesClusters[layerId][rofId]}; - return {&mClusters[layerId][startIdx], static_cast::size_type>(mROFramesClusters[layerId][rofId + 1] - startIdx)}; + return {&mClusters[layerId][startIdx], static_cast::size_type>(mROFramesClusters[layerId][rofId + 1] - startIdx)}; } -inline gsl::span TimeFrame::getUsedClustersROF(int rofId, int layerId) +template +inline gsl::span TimeFrame::getUsedClustersROF(int rofId, int layerId) { - if (rofId < 0 || rofId >= mNrof) { - return gsl::span(); + if (rofId < 0 || rofId >= getNrof(layerId)) { + return {}; } int startIdx{mROFramesClusters[layerId][rofId]}; - return {&mUsedClusters[layerId][startIdx], static_cast::size_type>(mROFramesClusters[layerId][rofId + 1] - startIdx)}; + return {&mUsedClusters[layerId][startIdx], static_cast::size_type>(mROFramesClusters[layerId][rofId + 1] - startIdx)}; } -inline gsl::span TimeFrame::getUsedClustersROF(int rofId, int layerId) const +template +inline gsl::span TimeFrame::getUsedClustersROF(int rofId, int layerId) const { - if (rofId < 0 || rofId >= mNrof) { - return gsl::span(); + if (rofId < 0 || rofId >= getNrof(layerId)) { + return {}; } int startIdx{mROFramesClusters[layerId][rofId]}; - return {&mUsedClusters[layerId][startIdx], static_cast::size_type>(mROFramesClusters[layerId][rofId + 1] - startIdx)}; + return {&mUsedClusters[layerId][startIdx], static_cast::size_type>(mROFramesClusters[layerId][rofId + 1] - startIdx)}; } -inline gsl::span TimeFrame::getClustersPerROFrange(int rofMin, int range, int layerId) const +template +inline gsl::span TimeFrame::getClustersPerROFrange(int rofMin, int range, int layerId) const { - if (rofMin < 0 || rofMin >= mNrof) { - return gsl::span(); + if (rofMin < 0 || rofMin >= getNrof(layerId)) { + return {}; } int startIdx{mROFramesClusters[layerId][rofMin]}; // First cluster of rofMin - int endIdx{mROFramesClusters[layerId][o2::gpu::CAMath::Min(rofMin + range, mNrof)]}; + int endIdx{mROFramesClusters[layerId][o2::gpu::CAMath::Min(rofMin + range, getNrof(layerId))]}; return {&mClusters[layerId][startIdx], static_cast::size_type>(endIdx - startIdx)}; } -inline gsl::span TimeFrame::getROFramesClustersPerROFrange(int rofMin, int range, int layerId) const +template +inline gsl::span TimeFrame::getROFramesClustersPerROFrange(int rofMin, int range, int layerId) const { - int chkdRange{o2::gpu::CAMath::Min(range, mNrof - rofMin)}; + int chkdRange{o2::gpu::CAMath::Min(range, getNrof(layerId) - rofMin)}; return {&mROFramesClusters[layerId][rofMin], static_cast::size_type>(chkdRange)}; } -inline gsl::span TimeFrame::getNClustersROFrange(int rofMin, int range, int layerId) const +template +inline gsl::span TimeFrame::getNClustersROFrange(int rofMin, int range, int layerId) const { - int chkdRange{o2::gpu::CAMath::Min(range, mNrof - rofMin)}; + int chkdRange{o2::gpu::CAMath::Min(range, getNrof(layerId) - rofMin)}; return {&mNClustersPerROF[layerId][rofMin], static_cast::size_type>(chkdRange)}; } -inline int TimeFrame::getTotalClustersPerROFrange(int rofMin, int range, int layerId) const +template +inline int TimeFrame::getTotalClustersPerROFrange(int rofMin, int range, int layerId) const { int startIdx{rofMin}; // First cluster of rofMin - int endIdx{o2::gpu::CAMath::Min(rofMin + range, mNrof)}; + int endIdx{o2::gpu::CAMath::Min(rofMin + range, getNrof(layerId))}; return mROFramesClusters[layerId][endIdx] - mROFramesClusters[layerId][startIdx]; } -inline gsl::span TimeFrame::getIndexTablePerROFrange(int rofMin, int range, int layerId) const -{ - const int iTableSize{mIndexTableUtils.getNphiBins() * mIndexTableUtils.getNzBins() + 1}; - int chkdRange{o2::gpu::CAMath::Min(range, mNrof - rofMin)}; - return {&mIndexTables[layerId][rofMin * iTableSize], static_cast::size_type>(chkdRange * iTableSize)}; -} - -inline int TimeFrame::getClusterROF(int iLayer, int iCluster) +template +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 TimeFrame::getUnsortedClustersOnLayer(int rofId, int layerId) const +template +inline gsl::span TimeFrame::getUnsortedClustersOnLayer(int rofId, int layerId) const { - if (rofId < 0 || rofId >= mNrof) { - return gsl::span(); + if (rofId < 0 || rofId >= getNrof(layerId)) { + return {}; } int startIdx{mROFramesClusters[layerId][rofId]}; return {&mUnsortedClusters[layerId][startIdx], static_cast::size_type>(mROFramesClusters[layerId][rofId + 1] - startIdx)}; } -inline const std::vector& TimeFrame::getTrackingFrameInfoOnLayer(int layerId) const +template +inline gsl::span TimeFrame::getIndexTable(int rofId, int layer) { - return mTrackingFrameInfo[layerId]; -} - -inline const TrackingFrameInfo& TimeFrame::getClusterTrackingFrameInfo(int layerId, const Cluster& cl) const -{ - return mTrackingFrameInfo[layerId][cl.clusterId]; -} - -inline const gsl::span TimeFrame::getClusterLabels(int layerId, const Cluster& cl) const -{ - return getClusterLabels(layerId, cl.clusterId); -} - -inline const gsl::span TimeFrame::getClusterLabels(int layerId, int clId) const -{ - return mClusterLabels->getLabels(mClusterExternalIndices[layerId][clId]); -} - -inline int TimeFrame::getClusterSize(int clusterId) const -{ - return mClusterSize[clusterId]; -} - -inline int TimeFrame::getClusterExternalIndex(int layerId, const int clId) const -{ - return mClusterExternalIndices[layerId][clId]; -} - -inline gsl::span TimeFrame::getIndexTable(int rofId, int layer) -{ - if (rofId < 0 || rofId >= mNrof) { - return gsl::span(); + if (rofId < 0 || rofId >= getNrof(layer)) { + return {}; } - return {&mIndexTables[layer][rofId * (mIndexTableUtils.getNphiBins() * mIndexTableUtils.getNzBins() + 1)], - static_cast::size_type>(mIndexTableUtils.getNphiBins() * mIndexTableUtils.getNzBins() + 1)}; -} - -inline std::vector& TimeFrame::getLines(int rofId) -{ - return mLines[rofId]; -} - -inline std::vector& TimeFrame::getTrackletClusters(int rofId) -{ - return mTrackletClusters[rofId]; + const int tableSize = mIndexTableUtils.getNphiBins() * mIndexTableUtils.getNzBins() + 1; + return {&mIndexTables[layer][rofId * tableSize], static_cast::size_type>(tableSize)}; } +template template -void TimeFrame::addClusterToLayer(int layer, T&&... values) +void TimeFrame::addClusterToLayer(int layer, T&&... values) { mUnsortedClusters[layer].emplace_back(std::forward(values)...); } +template template -void TimeFrame::addTrackingFrameInfoToLayer(int layer, T&&... values) +void TimeFrame::addTrackingFrameInfoToLayer(int layer, T&&... values) { mTrackingFrameInfo[layer].emplace_back(std::forward(values)...); } -inline void TimeFrame::addClusterExternalIndexToLayer(int layer, const int idx) -{ - mClusterExternalIndices[layer].push_back(idx); -} - -inline bool TimeFrame::hasMCinformation() const -{ - return mClusterLabels; -} - -inline bool TimeFrame::isClusterUsed(int layer, int clusterId) const -{ - return mUsedClusters[layer][clusterId]; -} - -inline gsl::span TimeFrame::getUsedClusters(const int layer) -{ - return {&mUsedClusters[layer][0], static_cast::size_type>(mUsedClusters[layer].size())}; -} - -inline void TimeFrame::markUsedCluster(int layer, int clusterId) { mUsedClusters[layer][clusterId] = true; } - -inline std::vector>& TimeFrame::getTracklets() -{ - return mTracklets; -} - -inline std::vector>& TimeFrame::getTrackletsLookupTable() -{ - return mTrackletsLookupTable; -} - -inline void TimeFrame::initialiseRoadLabels() +template +inline gsl::span TimeFrame::getUsedClusters(const int layer) { - mRoadLabels.clear(); - mRoadLabels.resize(mRoads.size()); + return {&mUsedClusters[layer][0], static_cast::size_type>(mUsedClusters[layer].size())}; } -inline void TimeFrame::setRoadLabel(int i, const unsigned long long& lab, bool fake) +template +inline gsl::span TimeFrame::getNTrackletsCluster(int rofId, int combId) { - mRoadLabels[i].first = lab; - mRoadLabels[i].second = fake; -} - -inline const unsigned long long& TimeFrame::getRoadLabel(int i) const -{ - return mRoadLabels[i].first; -} - -inline gsl::span TimeFrame::getNTrackletsCluster(int rofId, int combId) -{ - if (rofId < 0 || rofId >= mNrof) { - return gsl::span(); + if (rofId < 0 || rofId >= getNrof(1)) { + return {}; } auto startIdx{mROFramesClusters[1][rofId]}; return {&mNTrackletsPerCluster[combId][startIdx], static_cast::size_type>(mROFramesClusters[1][rofId + 1] - startIdx)}; } -inline gsl::span TimeFrame::getExclusiveNTrackletsCluster(int rofId, int combId) +template +inline gsl::span TimeFrame::getExclusiveNTrackletsCluster(int rofId, int combId) { - if (rofId < 0 || rofId >= mNrof) { - return gsl::span(); + if (rofId < 0 || rofId >= getNrof(1)) { + return {}; } auto clusStartIdx{mROFramesClusters[1][rofId]}; return {&mNTrackletsPerClusterSum[combId][clusStartIdx], static_cast::size_type>(mROFramesClusters[1][rofId + 1] - clusStartIdx)}; } -inline int& TimeFrame::getNTrackletsROF(int rofId, int combId) -{ - return mNTrackletsPerROF[combId][rofId]; -} - -inline bool TimeFrame::isRoadFake(int i) const -{ - return mRoadLabels[i].second; -} - -inline std::vector>& TimeFrame::getClusters() -{ - return mClusters; -} - -inline std::vector>& TimeFrame::getUnsortedClusters() -{ - return mUnsortedClusters; -} - -inline std::vector>& TimeFrame::getCells() { return mCells; } - -inline std::vector>& TimeFrame::getCellsLookupTable() +template +inline gsl::span TimeFrame::getFoundTracklets(int rofId, int combId) { - return mCellsLookupTable; -} - -inline std::vector>& TimeFrame::getCellsNeighbours() { return mCellsNeighbours; } -inline std::vector>& TimeFrame::getCellsNeighboursLUT() { return mCellsNeighboursLUT; } - -inline std::vector>& TimeFrame::getRoads() { return mRoads; } - -inline gsl::span TimeFrame::getFoundTracklets(int rofId, int combId) -{ - if (rofId < 0 || rofId >= mNrof) { - return gsl::span(); + if (rofId < 0 || rofId >= getNrof(1) || mTracklets[combId].empty()) { + return {}; } auto startIdx{mNTrackletsPerROF[combId][rofId]}; return {&mTracklets[combId][startIdx], static_cast::size_type>(mNTrackletsPerROF[combId][rofId + 1] - startIdx)}; } -inline gsl::span TimeFrame::getFoundTracklets(int rofId, int combId) const +template +inline gsl::span TimeFrame::getFoundTracklets(int rofId, int combId) const { - if (rofId < 0 || rofId >= mNrof) { - return gsl::span(); + if (rofId < 0 || rofId >= getNrof(1)) { + return {}; } auto startIdx{mNTrackletsPerROF[combId][rofId]}; return {&mTracklets[combId][startIdx], static_cast::size_type>(mNTrackletsPerROF[combId][rofId + 1] - startIdx)}; } -inline gsl::span TimeFrame::getLabelsFoundTracklets(int rofId, int combId) const +template +inline gsl::span TimeFrame::getLabelsFoundTracklets(int rofId, int combId) const { - if (rofId < 0 || rofId >= mNrof || !hasMCinformation()) { - return gsl::span(); + if (rofId < 0 || rofId >= getNrof(1) || !hasMCinformation()) { + return {}; } auto startIdx{mNTrackletsPerROF[combId][rofId]}; return {&mTrackletLabels[combId][startIdx], static_cast::size_type>(mNTrackletsPerROF[combId][rofId + 1] - startIdx)}; } -inline int TimeFrame::getNumberOfClusters() const +template +inline int TimeFrame::getTotalClusters() const { - int nClusters = 0; - for (auto& layer : mClusters) { + size_t totalClusters{0}; + for (const auto& clusters : mUnsortedClusters) { + totalClusters += clusters.size(); + } + return int(totalClusters); +} + +template +inline size_t TimeFrame::getNumberOfClusters() const +{ + size_t nClusters{0}; + for (const auto& layer : mClusters) { nClusters += layer.size(); } return nClusters; } -inline int TimeFrame::getNumberOfCells() const +template +inline size_t TimeFrame::getNumberOfCells() const { - int nCells = 0; - for (auto& layer : mCells) { + size_t nCells{0}; + for (const auto& layer : mCells) { nCells += layer.size(); } return nCells; } -inline int TimeFrame::getNumberOfTracklets() const +template +inline size_t TimeFrame::getNumberOfTracklets() const { - int nTracklets = 0; - for (auto& layer : mTracklets) { + size_t nTracklets{0}; + for (const auto& layer : mTracklets) { nTracklets += layer.size(); } return nTracklets; } -inline int TimeFrame::getNumberOfNeighbours() const +template +inline size_t TimeFrame::getNumberOfNeighbours() const { - int n{0}; - for (auto& l : mCellsNeighbours) { - n += l.size(); + size_t neigh{0}; + for (const auto& l : mCellsNeighbours) { + neigh += l.size(); } - return n; + return neigh; } -inline size_t TimeFrame::getNumberOfTracks() const +template +inline size_t TimeFrame::getNumberOfTracks() const { - int nTracks = 0; - for (auto& t : mTracks) { - nTracks += t.size(); - } - return nTracks; + return mTracks.size(); } -inline size_t TimeFrame::getNumberOfUsedClusters() const +template +inline size_t TimeFrame::getNumberOfUsedClusters() const { size_t nClusters = 0; - for (auto& layer : mUsedClusters) { + for (const auto& layer : mUsedClusters) { nClusters += std::count(layer.begin(), layer.end(), true); } return nClusters; } -inline void TimeFrame::insertPastVertex(const Vertex& vertex, const int iteration) -{ - int rofId = vertex.getTimeStamp().getTimeStamp(); - mPrimaryVertices.insert(mPrimaryVertices.begin() + mROFramesPV[rofId], vertex); - for (int i = rofId + 1; i < mROFramesPV.size(); ++i) { - mROFramesPV[i]++; - } - mTotVertPerIteration[iteration]++; -} - } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackHelpers.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackHelpers.h new file mode 100644 index 0000000000000..d244b39ff9d11 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackHelpers.h @@ -0,0 +1,303 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file TrackHelpers.h +/// \brief Shared host/device helpers for ITS tracker trait implementations +/// + +#ifndef O2_ITS_TRACKING_TRACKHELPERS_H_ +#define O2_ITS_TRACKING_TRACKHELPERS_H_ + +#include "DataFormatsITS/TrackITS.h" +#include "ITStracking/Cell.h" +#include "ITStracking/Cluster.h" +#include "ITStracking/Constants.h" +#include "ITStracking/MathUtils.h" +#include "DetectorsBase/Propagator.h" +#include "ReconstructionDataFormats/Track.h" + +namespace o2::its::track +{ + +// Prefer 1) longer track 2) sorted in chi2 +GPUhdi() bool isBetter(const o2::its::TrackITS& a, const o2::its::TrackITS& b) +{ + const auto ncla = a.getNumberOfClusters(); + const auto nclb = b.getNumberOfClusters(); + // is a as long as b ? then decide on chi2 + // otherwise prefer longer + return (ncla == nclb) ? (a.getChi2() < b.getChi2()) : ncla > nclb; +} + +// Find the populated interior layer closest to the radial midpoint. +// If no layer can be found, return constants::UnusedIndex. +// Should minimize the sagitta bias. +template +GPUdi() int selectReseedMidLayer(int minLayer, int maxLayer, const float* layerRadii, const TrackSeed& seed) +{ + int midLayer = constants::UnusedIndex; + float distanceToMidR = layerRadii[NLayers - 1]; // midpoint cannot be last layer + const float midR = 0.5f * (layerRadii[maxLayer] + layerRadii[minLayer]); + for (int iLayer = minLayer + 1; iLayer < maxLayer; ++iLayer) { + if (seed.getCluster(iLayer) != constants::UnusedIndex) { + const float distance = o2::gpu::CAMath::Abs(midR - layerRadii[iLayer]); + if (distance < distanceToMidR) { // keep the smaller-radius layer on ties + midLayer = iLayer; + distanceToMidR = distance; + } + } + } + return midLayer; +} + +GPUdi() void resetTrackCovariance(TrackITSExt& track) +{ + track.resetCovariance(); + track.setCov(track.getQ2Pt() * track.getQ2Pt() * track.getCov()[o2::track::CovLabels::kSigQ2Pt2], o2::track::CovLabels::kSigQ2Pt2); +} + +GPUdi() o2::track::TrackParCov buildTrackSeed(const Cluster& cluster1, + const Cluster& cluster2, + const TrackingFrameInfo& tf3, + const float bz, + const bool reverse = false) +{ + float ca = constants::UnsetValue, sa = constants::UnsetValue, snp = constants::UnsetValue, q2pt = constants::UnsetValue, q2pt2 = constants::UnsetValue; + o2::gpu::CAMath::SinCos(tf3.alphaTrackingFrame, sa, ca); + const float sign = reverse ? -1.f : 1.f; + const float x1 = (cluster1.xCoordinate * ca) + (cluster1.yCoordinate * sa); + const float y1 = (-cluster1.xCoordinate * sa) + (cluster1.yCoordinate * ca); + const float x2 = (cluster2.xCoordinate * ca) + (cluster2.yCoordinate * sa); + const float y2 = (-cluster2.xCoordinate * sa) + (cluster2.yCoordinate * ca); + const float x3 = tf3.xTrackingFrame; + const float y3 = tf3.positionTrackingFrame[0]; + if (o2::gpu::CAMath::Abs(bz) < 0.01f) { // zero field + const float dx = x3 - x1; + const float dy = y3 - y1; + snp = sign * dy / o2::gpu::CAMath::Hypot(dx, dy); + q2pt = 1.f / o2::track::kMostProbablePt; + q2pt2 = 1.f; + } else { + const float crv = math_utils::computeCurvature(x3, y3, x2, y2, x1, y1); + snp = sign * crv * (x3 - math_utils::computeCurvatureCentreX(x3, y3, x2, y2, x1, y1)); + q2pt = sign * crv / (bz * o2::constants::math::B2C); + q2pt2 = crv * crv; + } + const float tgl = -0.5f * sign * (math_utils::computeTanDipAngle(x1, y1, x2, y2, cluster1.zCoordinate, cluster2.zCoordinate) + math_utils::computeTanDipAngle(x2, y2, x3, y3, cluster2.zCoordinate, tf3.positionTrackingFrame[1])); + const float sg2q2pt = o2::track::kC1Pt2max * o2::gpu::CAMath::Clamp(q2pt2, 0.0005f, 1.0f); + return {x3, tf3.alphaTrackingFrame, {y3, tf3.positionTrackingFrame[1], snp, tgl, q2pt}, {tf3.covarianceTrackingFrame[0], tf3.covarianceTrackingFrame[1], tf3.covarianceTrackingFrame[2], 0.f, 0.f, o2::track::kCSnp2max, 0.f, 0.f, 0.f, o2::track::kCTgl2max, 0.f, 0.f, 0.f, 0.f, sg2q2pt}}; +} + +template +GPUdi() TrackITSExt seedTrackForRefit(const TrackSeed& seed, + const TrackingFrameInfo* const* foundTrackingFrameInfo, + const Cluster* const* unsortedClusters, + const float* layerRadii, + const float bz, + const int reseedIfShorter) +{ + TrackITSExt temporaryTrack(seed); + int lrMin = NLayers; + int lrMax = 0; + for (int iL{0}; iL < NLayers; ++iL) { + const int idx = seed.getCluster(iL); + temporaryTrack.setExternalClusterIndex(iL, idx, idx != constants::UnusedIndex); + if (idx != constants::UnusedIndex) { + lrMin = o2::gpu::CAMath::Min(lrMin, iL); + lrMax = o2::gpu::CAMath::Max(lrMax, iL); + } + } + + const int ncl = temporaryTrack.getNClusters(); + if (ncl < reseedIfShorter && ncl > 2) { + const int lrMid = selectReseedMidLayer(lrMin, lrMax, layerRadii, seed); + if (lrMid != constants::UnusedIndex) { + const auto& cluster0TF = foundTrackingFrameInfo[lrMin][seed.getCluster(lrMin)]; + const auto& cluster1GL = unsortedClusters[lrMid][seed.getCluster(lrMid)]; + const auto& cluster2GL = unsortedClusters[lrMax][seed.getCluster(lrMax)]; + temporaryTrack.getParamIn() = buildTrackSeed(cluster2GL, cluster1GL, cluster0TF, bz, true); + } + } + + resetTrackCovariance(temporaryTrack); + return temporaryTrack; +} + +GPUdi() bool fitTrack(TrackITSExt& trk, + int start, + int end, + int step, + float chi2clcut, + float chi2ndfcut, + float maxQoverPt, + int nCl, + const float bz, + const TrackingFrameInfo* const* tfInfos, + const float* layerxX0, + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType, + o2::track::TrackPar* linRef = nullptr, + const bool shiftRefToCluster = false) +{ + for (int iLayer{start}; iLayer != end; iLayer += step) { + if (trk.getClusterIndex(iLayer) == constants::UnusedIndex) { + continue; + } + + const TrackingFrameInfo& trackingHit = tfInfos[iLayer][trk.getClusterIndex(iLayer)]; + if (linRef) { + if (!trk.o2::track::TrackParCovF::rotate(trackingHit.alphaTrackingFrame, *linRef, bz)) { + return false; + } + if (!propagator->propagateToX(trk, *linRef, trackingHit.xTrackingFrame, bz, + o2::base::PropagatorImpl::MAX_SIN_PHI, + o2::base::PropagatorImpl::MAX_STEP, + matCorrType)) { + return false; + } + if (matCorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) { + if (!trk.correctForMaterial(*linRef, layerxX0[iLayer], layerxX0[iLayer] * constants::Radl * constants::Rho, true)) { + continue; + } + } + } else { + if (!trk.o2::track::TrackParCovF::rotate(trackingHit.alphaTrackingFrame)) { + return false; + } + if (!propagator->propagateToX(trk, trackingHit.xTrackingFrame, bz, + o2::base::PropagatorImpl::MAX_SIN_PHI, + o2::base::PropagatorImpl::MAX_STEP, + matCorrType)) { + return false; + } + if (matCorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) { + if (!trk.correctForMaterial(layerxX0[iLayer], layerxX0[iLayer] * constants::Radl * constants::Rho, true)) { + continue; + } + } + } + + const auto predChi2{trk.getPredictedChi2Quiet(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)}; + if ((nCl >= 3 && predChi2 > chi2clcut) || predChi2 < 0.f) { + return false; + } + trk.setChi2(trk.getChi2() + predChi2); + if (!trk.o2::track::TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) { + return false; + } + if (linRef && shiftRefToCluster) { + linRef->setY(trackingHit.positionTrackingFrame[0]); + linRef->setZ(trackingHit.positionTrackingFrame[1]); + } + nCl++; + } + + return o2::gpu::CAMath::Abs(trk.getQ2Pt()) < maxQoverPt && trk.getChi2() < chi2ndfcut * (float)((nCl * 2) - 5); +} + +template +GPUdi() bool refitTrack(const TrackSeed& trackSeed, + TrackITSExt& temporaryTrack, + float chi2clcut, + float chi2ndfcut, + const float bz, + const TrackingFrameInfo* const* tfInfos, + const Cluster* const* clusters, + const float* layerxX0, + const float* layerRadii, + const float* minPt, + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType, + const int reseedIfShorter, + const bool shiftRefToCluster, + const bool repeatRefitOut) +{ + temporaryTrack = seedTrackForRefit(trackSeed, + tfInfos, + clusters, + layerRadii, + bz, + reseedIfShorter); + o2::track::TrackPar linRef{temporaryTrack}; + bool fitSuccess = fitTrack(temporaryTrack, + 0, + NLayers, + 1, + chi2clcut, + chi2ndfcut, + o2::constants::math::VeryBig, + 0, + bz, + tfInfos, + layerxX0, + propagator, + matCorrType, + &linRef, + shiftRefToCluster); + if (!fitSuccess) { + return false; + } + temporaryTrack.getParamOut() = temporaryTrack.getParamIn(); + linRef = temporaryTrack.getParamOut(); // use refitted track as lin.reference + resetTrackCovariance(temporaryTrack); + temporaryTrack.setChi2(0); + fitSuccess = fitTrack(temporaryTrack, + NLayers - 1, + -1, + -1, + chi2clcut, + chi2ndfcut, + 50.f, + 0, + bz, + tfInfos, + layerxX0, + propagator, + matCorrType, + &linRef, + shiftRefToCluster); + if (!fitSuccess || temporaryTrack.getPt() < minPt[NLayers - temporaryTrack.getNClusters()]) { + return false; + } + if (repeatRefitOut) { // repeat outward refit seeding and linearizing with the stable inward fit result + o2::track::TrackParCov saveInw{temporaryTrack}; + linRef = saveInw; // use refitted track as lin.reference + float saveChi2 = temporaryTrack.getChi2(); + track::resetTrackCovariance(temporaryTrack); + temporaryTrack.setChi2(0); + fitSuccess = o2::its::track::fitTrack(temporaryTrack, + 0, + NLayers, + 1, + chi2clcut, + chi2ndfcut, + o2::constants::math::VeryBig, + 0, + bz, + tfInfos, + layerxX0, + propagator, + matCorrType, + &linRef, + shiftRefToCluster); + if (!fitSuccess) { + return false; + } + temporaryTrack.getParamOut() = temporaryTrack.getParamIn(); + temporaryTrack.getParamIn() = saveInw; + temporaryTrack.setChi2(saveChi2); + } + return true; +} + +} // namespace o2::its::track + +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracker.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracker.h index 8f0a471b40c59..240b0eb1e2f63 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracker.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracker.h @@ -18,24 +18,22 @@ #include #include -#include #include #include #include #include +#include #include #include +#include + +#include #include "ITStracking/Configuration.h" -#include "CommonConstants/MathConstants.h" #include "ITStracking/Definitions.h" -#include "ITStracking/ROframe.h" -#include "ITStracking/MathUtils.h" #include "ITStracking/TimeFrame.h" -#include "ITStracking/Road.h" - -#include "DataFormatsITS/TrackITS.h" -#include "SimulationDataFormat/MCCompLabel.h" +#include "ITStracking/TrackerTraits.h" +#include "ITStracking/BoundedAllocator.h" namespace o2 { @@ -46,98 +44,108 @@ class GPUChainITS; } namespace its { -class TrackerTraits; +template class Tracker { using LogFunc = std::function; public: - Tracker(TrackerTraits* traits); + Tracker(TrackerTraits* traits); - void adoptTimeFrame(TimeFrame& tf); + void adoptTimeFrame(TimeFrame& tf); - void clustersToTracks(LogFunc = [](std::string s) { std::cout << s << std::endl; }, LogFunc = [](std::string s) { std::cerr << s << std::endl; }); + float clustersToTracks( + const LogFunc& = [](const std::string& s) { std::cout << s << '\n'; }, + const LogFunc& = [](const std::string& s) { std::cerr << s << '\n'; }); - void setParameters(const std::vector&); + void setParameters(const std::vector& p) { mTrkParams = p; } + void setMemoryPool(std::shared_ptr pool) { mMemoryPool = pool; } std::vector& getParameters() { return mTrkParams; } - void getGlobalConfiguration(); - void setBz(float); - void setCorrType(const o2::base::PropagatorImpl::MatCorrType type); - bool isMatLUT() const; - void setNThreads(int n); - int getNThreads() const; + void setBz(float bz) { mTraits->setBz(bz); } + void setTimeSlice(size_t slice) noexcept { mTimeSlice = slice; } + void setNThreads(int n, std::shared_ptr& arena) { mTraits->setNThreads(n, arena); } void printSummary() const; + void computeTracksMClabels(); private: - void initialiseTimeFrame(int& iteration); - void computeTracklets(int& iteration, int& iROFslice, int& iVertex); - void computeCells(int& iteration); - void findCellsNeighbours(int& iteration); - void findRoads(int& iteration); - void findShortPrimaries(); - void extendTracks(int& iteration); - - // MC interaction - void computeRoadsMClabels(); - void computeTracksMClabels(); + void initialiseTimeFrame(int iteration) { mTraits->initialiseTimeFrame(iteration); } + void computeTracklets(int iteration, int iVertex) { mTraits->computeLayerTracklets(iteration, iVertex); } + void computeCells(int iteration) { mTraits->computeLayerCells(iteration); } + void findCellsNeighbours(int iteration) { mTraits->findCellsNeighbours(iteration); } + void findRoads(int iteration) { mTraits->findRoads(iteration); } + void rectifyClusterIndices(); + void sortTracks(); - template - float evaluateTask(void (Tracker::*)(T...), const char*, LogFunc logger, T&&... args); + template + float evaluateTask(void (Tracker::*task)(T...), std::string_view taskName, int iteration, const LogFunc& logger, F&&... args); - TrackerTraits* mTraits = nullptr; /// Observer pointer, not owned by this class - TimeFrame* mTimeFrame = nullptr; /// Observer pointer, not owned by this class + TrackerTraits* mTraits = nullptr; /// Observer pointer, not owned by this class + TimeFrame* mTimeFrame = nullptr; /// Observer pointer, not owned by this class std::vector mTrkParams; o2::gpu::GPUChainITS* mRecoChain = nullptr; + size_t mTimeSlice{0}; // current timeslice unsigned int mNumberOfDroppedTFs{0}; unsigned int mTimeFrameCounter{0}; double mTotalTime{0}; + std::shared_ptr mMemoryPool; + + enum Steps { + TFInit = 0, + Trackleting, + Celling, + Neighbouring, + Roading, + NSteps, + }; + Steps mCurStep{TFInit}; + static constexpr std::array StateNames{"TimeFrame initialisation", "Tracklet finding", "Cell finding", "Neighbour finding", "Road finding"}; + std::vector> mTimingStats; + void addTimingStatCurStep(int iteration, double timeMs); }; -inline void Tracker::setParameters(const std::vector& trkPars) -{ - mTrkParams = trkPars; -} - -template -float Tracker::evaluateTask(void (Tracker::*task)(T...), const char* taskName, LogFunc logger, T&&... args) +template +template +float Tracker::evaluateTask(void (Tracker::*task)(T...), std::string_view taskName, int iteration, const LogFunc& logger, F&&... args) { float diff{0.f}; if constexpr (constants::DoTimeBenchmarks) { auto start = std::chrono::high_resolution_clock::now(); - (this->*task)(std::forward(args)...); + (this->*task)(std::forward(args)...); auto end = std::chrono::high_resolution_clock::now(); std::chrono::duration diff_t{end - start}; diff = diff_t.count(); std::stringstream sstream; - if (taskName == nullptr) { + if (taskName.empty()) { sstream << diff << "\t"; } else { sstream << std::setw(2) << " - " << taskName << " completed in: " << diff << " ms"; } logger(sstream.str()); - if (mTrkParams[0].SaveTimeBenchmarks) { - std::stringstream str2file; + if (mTrkParams[iteration].SaveTimeBenchmarks) { std::string taskNameStr(taskName); std::transform(taskNameStr.begin(), taskNameStr.end(), taskNameStr.begin(), [](unsigned char c) { return std::tolower(c); }); std::replace(taskNameStr.begin(), taskNameStr.end(), ' ', '_'); - str2file << taskNameStr << "\t" << diff; - std::ofstream file; - file.open("its_time_benchmarks.txt", std::ios::app); - file << str2file.str() << std::endl; - file.close(); + if (std::ofstream file{"its_time_benchmarks.txt", std::ios::app}) { + file << "trk:" << iteration << '\t' << taskNameStr << '\t' << diff << '\n'; + } + addTimingStatCurStep(iteration, diff); } } else { - (this->*task)(std::forward(args)...); + (this->*task)(std::forward(args)...); + } + + if (mTrkParams[iteration].PrintMemory) { + LOGP(info, "iter:{}:{}: {}", iteration, StateNames[mCurStep], mMemoryPool->asString()); } return diff; diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h index 6b514c6e8d000..f536e86fe95d5 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h @@ -16,12 +16,13 @@ #ifndef TRACKINGITSU_INCLUDE_TRACKERTRAITS_H_ #define TRACKINGITSU_INCLUDE_TRACKERTRAITS_H_ -#include +#include -#include "DetectorsBase/Propagator.h" #include "ITStracking/Configuration.h" -#include "ITStracking/MathUtils.h" +#include "ITStracking/IndexTableUtils.h" #include "ITStracking/TimeFrame.h" +#include "ITStracking/Cell.h" +#include "ITStracking/BoundedAllocator.h" // #define OPTIMISATION_OUTPUT @@ -35,113 +36,62 @@ namespace its { class TrackITSExt; +template class TrackerTraits { public: + using IndexTableUtilsN = IndexTableUtils; + using TrackSeedN = TrackSeed; + virtual ~TrackerTraits() = default; - virtual void adoptTimeFrame(TimeFrame* tf); - virtual void initialiseTimeFrame(const int iteration); + virtual void adoptTimeFrame(TimeFrame* tf) { mTimeFrame = tf; } + virtual void initialiseTimeFrame(const int iteration) { mTimeFrame->initialise(mTrkParams[iteration], mTrkParams[iteration].NLayers, iteration); } - virtual void computeLayerTracklets(const int iteration, int iROFslice, int iVertex); + virtual void computeLayerTracklets(const int iteration, int iVertex); virtual void computeLayerCells(const int iteration); virtual void findCellsNeighbours(const int iteration); virtual void findRoads(const int iteration); - virtual bool supportsExtendTracks() const noexcept { return true; } - virtual void extendTracks(const int iteration); - virtual bool supportsFindShortPrimaries() const noexcept { return true; } - virtual void findShortPrimaries(); + template + void processNeighbours(int iteration, int defaultCellTopologyId, int iLevel, const bounded_vector& currentCellSeed, const bounded_vector& currentCellId, const bounded_vector& currentCellTopologyId, bounded_vector& updatedCellSeed, bounded_vector& updatedCellId, bounded_vector& updatedCellTopologyId); - virtual bool trackFollowing(TrackITSExt* track, int rof, bool outward, const int iteration); - virtual void processNeighbours(int iLayer, int iLevel, const std::vector& currentCellSeed, const std::vector& currentCellId, std::vector& updatedCellSeed, std::vector& updatedCellId); + void acceptTracks(int iteration, bounded_vector& tracks, bounded_vector>& firstClusters); + void markTracks(int iteration); - void UpdateTrackingParameters(const std::vector& trkPars); - TimeFrame* getTimeFrame() { return mTimeFrame; } + void updateTrackingParameters(const std::vector& trkPars) + { + mTrkParams = trkPars; + } + TimeFrame* getTimeFrame() { return mTimeFrame; } virtual void setBz(float bz); - float getBz() const; - void setCorrType(const o2::base::PropagatorImpl::MatCorrType type) { mCorrType = type; } - bool isMatLUT() const; + float getBz() const { return mBz; } virtual const char* getName() const noexcept { return "CPU"; } virtual bool isGPU() const noexcept { return false; } + void setMemoryPool(std::shared_ptr pool) noexcept { mMemoryPool = pool; } + auto getMemoryPool() const noexcept { return mMemoryPool; } // Others - GPUhd() static consteval int4 getEmptyBinsRect() { return int4{0, 0, 0, 0}; } - const int4 getBinsRect(const Cluster&, int layer, float z1, float z2, float maxdeltaz, float maxdeltaphi) const noexcept; - const int4 getBinsRect(int layer, float phi, float maxdeltaphi, float z, float maxdeltaz) const noexcept; - const int4 getBinsRect(int layer, float phi, float maxdeltaphi, float z1, float z2, float maxdeltaz) const noexcept; - void SetRecoChain(o2::gpu::GPUChainITS* chain) { mChain = chain; } - void setSmoothing(bool v) { mApplySmoothing = v; } - bool getSmoothing() const { return mApplySmoothing; } - void setNThreads(int n); - int getNThreads() const { return mNThreads; } - - o2::gpu::GPUChainITS* getChain() const { return mChain; } + void setNThreads(int n, std::shared_ptr& arena); + int getNThreads() { return mTaskArena->max_concurrency(); } // TimeFrame information forwarding - virtual int getTFNumberOfClusters() const; - virtual int getTFNumberOfTracklets() const; - virtual int getTFNumberOfCells() const; - - float mBz = 5.f; + virtual int getTFNumberOfClusters() const { return mTimeFrame->getNumberOfClusters(); } + virtual int getTFNumberOfTracklets() const { return mTimeFrame->getNumberOfTracklets(); } + virtual int getTFNumberOfCells() const { return mTimeFrame->getNumberOfCells(); } private: - track::TrackParCov buildTrackSeed(const Cluster& cluster1, const Cluster& cluster2, const TrackingFrameInfo& tf3); - bool fitTrack(TrackITSExt& track, int start, int end, int step, float chi2clcut = o2::constants::math::VeryBig, float chi2ndfcut = o2::constants::math::VeryBig, float maxQoverPt = o2::constants::math::VeryBig, int nCl = 0); - - int mNThreads = 1; - bool mApplySmoothing = false; + std::shared_ptr mMemoryPool; + std::shared_ptr mTaskArena; protected: - o2::base::PropagatorImpl::MatCorrType mCorrType = o2::base::PropagatorImpl::MatCorrType::USEMatCorrNONE; o2::gpu::GPUChainITS* mChain = nullptr; - TimeFrame* mTimeFrame; + TimeFrame* mTimeFrame; std::vector mTrkParams; -}; - -inline void TrackerTraits::initialiseTimeFrame(const int iteration) -{ - mTimeFrame->initialise(iteration, mTrkParams[iteration], mTrkParams[iteration].NLayers); -} - -inline float TrackerTraits::getBz() const -{ - return mBz; -} - -inline void TrackerTraits::UpdateTrackingParameters(const std::vector& trkPars) -{ - mTrkParams = trkPars; -} - -inline const int4 TrackerTraits::getBinsRect(const int layerIndex, float phi, float maxdeltaphi, float z, float maxdeltaz) const noexcept -{ - return getBinsRect(layerIndex, phi, maxdeltaphi, z, z, maxdeltaz); -} - -inline const int4 TrackerTraits::getBinsRect(const Cluster& currentCluster, int layerIndex, float z1, float z2, float maxdeltaz, float maxdeltaphi) const noexcept -{ - return getBinsRect(layerIndex, currentCluster.phi, maxdeltaphi, z1, z2, maxdeltaz); -} -inline const int4 TrackerTraits::getBinsRect(const int layerIndex, float phi, float maxdeltaphi, float z1, float z2, float maxdeltaz) const noexcept -{ - const float zRangeMin = o2::gpu::GPUCommonMath::Min(z1, z2) - maxdeltaz; - const float phiRangeMin = (maxdeltaphi > constants::math::Pi) ? 0.f : phi - maxdeltaphi; - const float zRangeMax = o2::gpu::GPUCommonMath::Max(z1, z2) + maxdeltaz; - const float phiRangeMax = (maxdeltaphi > constants::math::Pi) ? constants::math::TwoPi : phi + maxdeltaphi; - - if (zRangeMax < -mTrkParams[0].LayerZ[layerIndex] || - zRangeMin > mTrkParams[0].LayerZ[layerIndex] || zRangeMin > zRangeMax) { - return getEmptyBinsRect(); - } + float mBz{-999.f}; +}; - const IndexTableUtils& utils{mTimeFrame->mIndexTableUtils}; - return int4{o2::gpu::GPUCommonMath::Max(0, utils.getZBinIndex(layerIndex, zRangeMin)), - utils.getPhiBinIndex(math_utils::getNormalizedPhi(phiRangeMin)), - o2::gpu::GPUCommonMath::Min(mTrkParams[0].ZBins - 1, utils.getZBinIndex(layerIndex, zRangeMax)), // /!\ trkParams can potentially change across iterations - utils.getPhiBinIndex(math_utils::getNormalizedPhi(phiRangeMax))}; -} } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h index cb6512248bf0c..69aa3c5fdaf06 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h @@ -12,60 +12,70 @@ #ifndef ALICEO2_ITSDPLTRACKINGPARAM_H_ #define ALICEO2_ITSDPLTRACKINGPARAM_H_ +#include #include "CommonUtils/ConfigurableParam.h" #include "CommonUtils/ConfigurableParamHelper.h" +#include "ITStracking/Constants.h" -namespace o2 -{ -namespace its +namespace o2::its { struct VertexerParamConfig : public o2::conf::ConfigurableParamHelper { + bool saveTimeBenchmarks = false; // dump metrics on file - int nIterations = 1; // Number of vertexing passes to perform. - int vertPerRofThreshold = 0; // Maximum number of vertices per ROF to trigger second a iteration. - bool allowSingleContribClusters = false; // attempt to find vertices in case of a single tracklet found. - int deltaRof = 0; // Number of ROFs to be considered for the vertexing. + int nIterations = 1; // Number of vertexing passes to perform. + int vertPerRofThreshold = 0; // Maximum number of vertices per ROF to trigger second a iteration. - // geometrical cuts for tracklet selection + // geometrical cuts for tracklet selection for Pb-Pb float zCut = 0.002f; float phiCut = 0.005f; - float pairCut = 0.04f; - float clusterCut = 0.8f; - float histPairCut = 0.04f; - float tanLambdaCut = 0.002f; // tanLambda = deltaZ/deltaR - float lowMultBeamDistCut = 0.1f; // XY cut for low-multiplicity pile up - int vertNsigmaCut = 4; // N sigma cut for vertex XY - float vertRadiusSigma = 0.05f; // sigma of vertex XY - float trackletSigma = 0.01f; // tracklet to vertex sigma + float pairCut = 0.017321f; + float clusterCut = 0.170048f; + float coarseZWindow = 0.055458f; + float seedDedupZCut = 0.116685f; + float refitDedupZCut = 0.039855f; + float duplicateZCut = 0.200097f; + float finalSelectionZCut = 0.034535f; + float duplicateDistance2Cut = 0.005117f; + float tanLambdaCut = 0.002f; // tanLambda = deltaZ/deltaR + float nSigmaCut = 0.0164651f; float maxZPositionAllowed = 25.f; // 4x sZ of the beam // Artefacts selections - int clusterContributorsCut = 16; // minimum number of contributors for the second vertex found in the same ROF (pileup cut) - int maxTrackletsPerCluster = 1e2; + int clusterContributorsCut = 3; // minimum number of contributors for an accepted final vertex + int suppressLowMultDebris = 16; // suppress all vertices below this threshold if a vertex was already found in a rof + int seedMemberRadiusTime = 0; + int seedMemberRadiusZ = 2; + int maxTrackletsPerCluster = 100; int phiSpan = -1; int zSpan = -1; int ZBins = 1; // z-phi index table configutation: number of z bins int PhiBins = 128; // z-phi index table configutation: number of phi bins + bool useTruthSeeding{false}; // overwrite seeding vertices with MC truth + int nThreads = 1; + bool printMemory = false; + size_t maxMemory = std::numeric_limits::max(); + bool dropTFUponFailure = false; O2ParamDef(VertexerParamConfig, "ITSVertexerParam"); }; struct TrackerParamConfig : public o2::conf::ConfigurableParamHelper { - // Use TGeo for mat. budget - static const int MaxIter = 4; static const int MinTrackLength = 4; static const int MaxTrackLength = 7; - bool useMatCorrTGeo = false; // use full geometry to corect for material budget accounting in the fits. Default is to use the material budget LUT. - bool useFastMaterial = false; // use faster material approximation for material budget accounting in the fits. - int deltaRof = 0; // configure the width of the window in ROFs to be considered for the tracking. - int minTrackLgtIter[MaxIter] = {}; // minimum track length at each iteration, used only if >0, otherwise use code defaults - uint8_t startLayerMask[MaxIter] = {}; // mask of start layer for this iteration (if >0) - float minPtIterLgt[MaxIter * (MaxTrackLength - MinTrackLength + 1)] = {}; // min.pT for given track length at this iteration, used only if >0, otherwise use code defaults - float sysErrY2[7] = {0}; // systematic error^2 in Y per layer - float sysErrZ2[7] = {0}; // systematic error^2 in Z per layer + + bool useMatCorrTGeo = false; // use full geometry to corect for material budget accounting in the fits. Default is to use the material budget LUT. + bool useFastMaterial = false; // use faster material approximation for material budget accounting in the fits. + int addTimeError[7] = {0}; // configure the width of the window in BC to be considered for the tracking. + int minTrackLgtIter[constants::MaxIter] = {}; // minimum track length at each iteration, used only if >0, otherwise use code defaults + uint8_t startLayerMask[constants::MaxIter] = {}; // mask of start layer for this iteration (if >0) + int maxHolesIter[constants::MaxIter] = {}; // maximum number of missing internal layers allowed in the CA topology for each iteration + uint16_t holeLayerMaskIter[constants::MaxIter] = {}; // layers that may be skipped by the CA topology for each iteration + float minPtIterLgt[constants::MaxIter * (MaxTrackLength - MinTrackLength + 1)] = {}; // min.pT for given track length at this iteration, used only if >0, otherwise use code defaults + float sysErrY2[7] = {0}; // systematic error^2 in Y per layer + float sysErrZ2[7] = {0}; // systematic error^2 in Z per layer float maxChi2ClusterAttachment = -1.f; float maxChi2NDF = -1.f; float nSigmaCut = -1.f; @@ -74,38 +84,33 @@ struct TrackerParamConfig : public o2::conf::ConfigurableParamHelper 0 off - float trackFollowerNSigmaZ = 1.f; // sigma in z-cut for track-following search rectangle - float trackFollowerNSigmaPhi = 1.f; // sigma in phi-cut for track-following search rectangle - float cellsPerClusterLimit = -1.f; - float trackletsPerClusterLimit = -1.f; - int findShortTracks = -1; - int nThreads = 1; // number of threads to perform the operations in parallel. - int nROFsPerIterations = 0; // size of the slice of ROFs to be processed at a time, preferably integer divisors of nROFs per TF, to balance the iterations. - int nOrbitsPerIterations = 0; // not implemented: size of the slice of ROFs to be processed at a time, computed using the number of ROFs per orbit. + float diamondPos[3] = {0.f, 0.f, 0.f}; // override the position of the vertex + bool useDiamond = false; // enable overriding the vertex position bool perPrimaryVertexProcessing = false; // perform the full tracking considering the vertex hypotheses one at the time. bool saveTimeBenchmarks = false; // dump metrics on file bool overrideBeamEstimation = false; // use beam position from meanVertex CCDB object int trackingMode = -1; // -1: unset, 0=sync, 1=async, 2=cosmics used by gpuwf only bool doUPCIteration = false; // Perform an additional iteration for UPC events on tagged vertices. You want to combine this config with VertexerParamConfig.nIterations=2 - bool fataliseUponFailure = true; // granular management of the fatalisation in async mode - bool dropTFUponFailure = false; + int nIterations = constants::MaxIter; // overwrite the number of iterations + int reseedIfShorter = 6; // for the final refit reseed the track with circle if they are shorter than this value + bool shiftRefToCluster{true}; // TrackFit: after update shift the linearization reference to cluster + bool repeatRefitOut{false}; // repeat outward refit using inward refit as a seed + bool createArtefactLabels{false}; // create on-the-fly labels for the artefacts - O2ParamDef(TrackerParamConfig, "ITSCATrackerParam"); -}; + int nThreads = 1; + bool printMemory = false; + size_t maxMemory = std::numeric_limits::max(); + bool dropTFUponFailure = false; + bool fataliseUponFailure = true; // granular management of the fatalisation in async mode -struct ITSGpuTrackingParamConfig : public o2::conf::ConfigurableParamHelper { - // GPU-specific parameters - unsigned int tmpCUBBufferSize = 1e5; // In average in pp events there are required 4096 bytes - int nBlocks = 20; - int nThreads = 256; + // Selections on tracks sharing clusters + bool allowSharingFirstCluster = false; // allow first cluster sharing among tracks + float sharedClusterMaxDeltaPhi = 0.05f; // Maximum allowed delta phi at the cluster position + float sharedClusterMaxDeltaEta = 0.03f; // Maximum allowed delta eta at the cluster position + bool sharedClusterOppositeSign = false; // Require opposite sign of the tracklets - O2ParamDef(ITSGpuTrackingParamConfig, "ITSGpuTrackingParam"); + O2ParamDef(TrackerParamConfig, "ITSCATrackerParam"); }; -} // namespace its -} // namespace o2 +} // namespace o2::its #endif diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingInterface.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingInterface.h index 6eacb94ebb1ea..14c5d6a62e0ad 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingInterface.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingInterface.h @@ -19,23 +19,35 @@ #include "ITStracking/TrackerTraits.h" #include "ITStracking/Vertexer.h" #include "ITStracking/VertexerTraits.h" +#include "ITStracking/BoundedAllocator.h" #include "DataFormatsParameters/GRPObject.h" #include "DataFormatsITSMFT/TopologyDictionary.h" #include "DataFormatsCalibration/MeanVertexObject.h" -#include "GPUDataTypes.h" -#include "GPUO2Interface.h" +#include "GPUDataTypesIO.h" +#include "GPUO2ExternalUser.h" #include "GPUChainITS.h" +#include + namespace o2::its { class ITSTrackingInterface { public: + static constexpr int NLayers{7}; + using VertexerN = Vertexer; + using VertexerTraitsN = VertexerTraits; + using TrackerN = Tracker; + using TrackerTraitsN = TrackerTraits; + using TimeFrameN = TimeFrame; + ITSTrackingInterface(bool isMC, + bool doStag, int trgType, const bool overrBeamEst) : mIsMC{isMC}, + mDoStaggering(doStag), mUseTriggers{trgType}, mOverrideBeamEstimation{overrBeamEst} {} @@ -52,7 +64,6 @@ class ITSTrackingInterface } // Task callbacks void initialise(); - template void run(framework::ProcessingContext& pc); void printSummary() const; @@ -60,38 +71,38 @@ class ITSTrackingInterface virtual void finaliseCCDB(framework::ConcreteDataMatcher& matcher, void* obj); // Custom - void setTraitsFromProvider(VertexerTraits*, TrackerTraits*, TimeFrame*); - void setTrackingMode(TrackingMode mode = TrackingMode::Unset) - { - if (mode == TrackingMode::Unset) { - LOGP(fatal, "ITS Tracking mode Unset is meant to be a default. Specify the mode"); - } - mMode = mode; - } + void setTraitsFromProvider(VertexerTraitsN*, TrackerTraitsN*, TimeFrameN*); + void setTrackingMode(TrackingMode::Type mode = TrackingMode::Unset) { mMode = mode; } auto getTracker() const { return mTracker.get(); } auto getVertexer() const { return mVertexer.get(); } - TimeFrame* mTimeFrame = nullptr; + TimeFrameN* mTimeFrame = nullptr; protected: - virtual void loadROF(gsl::span& trackROFspan, + virtual void overrideParameters(std::vector& t, std::vector& v) {} + virtual void requestTopologyDictionary(framework::ProcessingContext& pc); + virtual void loadROF(gsl::span& trackROFspan, gsl::span clusters, gsl::span::iterator& pattIt, + int layer, const dataformats::MCTruthContainer* mcLabels); - void getConfiguration(framework::ProcessingContext& pc); private: bool mIsMC = false; + bool mDoStaggering = false; bool mRunVertexer = true; bool mCosmicsProcessing = false; int mUseTriggers = 0; - TrackingMode mMode = TrackingMode::Unset; + std::vector mFilter; + TrackingMode::Type mMode = TrackingMode::Unset; bool mOverrideBeamEstimation = false; const o2::itsmft::TopologyDictionary* mDict = nullptr; - std::unique_ptr mTracker = nullptr; - std::unique_ptr mVertexer = nullptr; - const o2::dataformats::MeanVertexObject* mMeanVertex; + std::unique_ptr mTracker = nullptr; + std::unique_ptr mVertexer = nullptr; + const o2::dataformats::MeanVertexObject* mMeanVertex{}; + std::shared_ptr mMemoryPool; + std::shared_ptr mTaskArena; }; } // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingTopology.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingTopology.h new file mode 100644 index 0000000000000..2afb67609664f --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingTopology.h @@ -0,0 +1,219 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef TRACKINGITSU_INCLUDE_TRACKINGTOPOLOGY_H_ +#define TRACKINGITSU_INCLUDE_TRACKINGTOPOLOGY_H_ + +#include +#include +#include +#include + +#ifndef GPUCA_GPUCODE +#include +#include +#include "Framework/Logger.h" +#endif + +#include "CommonDataFormat/RangeReference.h" +#include "GPUCommonDef.h" +#include "GPUCommonMath.h" +#include "ITStracking/LayerMask.h" + +namespace o2::its +{ + +template +class TrackingTopology +{ + public: + using Id = uint8_t; + using Mask = LayerMask; + using Range = o2::dataformats::RangeReference; + static constexpr int MaxTransitions = (NLayers * (NLayers - 1)) / 2; + static constexpr int MaxCells = (NLayers * (NLayers - 1) * (NLayers - 2)) / 6; + static_assert(NLayers < std::numeric_limits::max()); + static_assert(MaxTransitions <= std::numeric_limits::max()); + static_assert(MaxCells <= std::numeric_limits::max()); + + // Describes from which layer to which layer the look-up happens + struct LayerTransition { + Id fromLayer{0}; + Id toLayer{0}; + }; + static_assert(std::is_standard_layout_v); + static_assert(std::is_trivially_copyable_v); + static_assert(sizeof(LayerTransition) == (2 * sizeof(Id))); + + // Describes from which LayerTransition a tracklet is allowed to originate + // and with which LayerTransition this can be combined additionally the hitMasked is cached + struct CellTopology { + Id firstTransition{0}; + Id secondTransition{0}; + Mask hitLayerMask{0}; + }; + static_assert(std::is_standard_layout_v); + static_assert(std::is_trivially_copyable_v); + static_assert(sizeof(CellTopology) == (2 * sizeof(Id)) + sizeof(Mask)); + + // GPU ready view of the underlying LUTs + struct View { + const LayerTransition* transitions{nullptr}; + const CellTopology* cells{nullptr}; + const Range* cellsByFirstTransitionIndex{nullptr}; + const Id* cellsByFirstTransition{nullptr}; + Id nTransitions{0}; + Id nCells{0}; + Id nCellsByFirstTransition{0}; + + GPUhdi() const LayerTransition& getTransition(Id id) const { return transitions[id]; } + GPUhdi() const CellTopology& getCell(Id id) const { return cells[id]; } + GPUhdi() Range getCellsStartingWithTransition(Id transitionId) const { return cellsByFirstTransitionIndex[transitionId]; } + +#ifndef GPUCA_GPUCODE + std::string asString() const + { + std::string out = fmt::format("TrackingTopology: transitions={} cells={}", nTransitions, nCells); + out += "\n transitions:"; + for (Id transitionId = 0; transitionId < nTransitions; ++transitionId) { + const auto& t = transitions[transitionId]; + out += fmt::format("\n {}: {} -> {}", transitionId, t.fromLayer, t.toLayer); + } + out += "\n cells:"; + for (Id cellId = 0; cellId < nCells; ++cellId) { + const auto& c = cells[cellId]; + const auto& first = transitions[c.firstTransition]; + const auto& second = transitions[c.secondTransition]; + out += fmt::format("\n {}: {} -> {} -> {} hitMask={} transitions=({}, {})", cellId, first.fromLayer, first.toLayer, second.toLayer, c.hitLayerMask.asString(), c.firstTransition, c.secondTransition); + } + return out; + } + + void print() const + { + LOGP(info, "{}", asString()); + } +#endif + }; + + void init(int maxLayers, int maxHoles, Mask holeLayerMask) + { + clear(); + mMaxLayers = o2::gpu::CAMath::Max(0, o2::gpu::CAMath::Min(maxLayers, NLayers)); + mMaxHoles = o2::gpu::CAMath::Max(maxHoles, 0); + mHoleLayerMask = holeLayerMask; + for (int fromLayer = 0; fromLayer < mMaxLayers; ++fromLayer) { + for (int toLayer = fromLayer + 1; toLayer < mMaxLayers; ++toLayer) { + if (Mask::skipped(fromLayer, toLayer).isAllowedHoleMask(mMaxHoles, mHoleLayerMask)) { + mTransitions[mNTransitions++] = LayerTransition{static_cast(fromLayer), static_cast(toLayer)}; + } + } + } + + for (Id firstId = 0; firstId < mNTransitions; ++firstId) { + const auto& first = mTransitions[firstId]; + for (Id secondId = 0; secondId < mNTransitions; ++secondId) { + const auto& second = mTransitions[secondId]; + if (first.toLayer != second.fromLayer) { + continue; + } + const Mask hitMask{first.fromLayer, first.toLayer, second.toLayer}; + if (hitMask.isAllowed(mMaxHoles, mHoleLayerMask)) { + mCells[mNCells++] = CellTopology{firstId, secondId, hitMask}; + } + } + } + + fillCellsByTransition(); + } + + View getView() const + { + return View{mTransitions.data(), + mCells.data(), + mCellsByFirstTransitionIndex.data(), + mCellsByFirstTransition.data(), + mNTransitions, + mNCells, + mNCellsByFirstTransition}; + } + + View getDeviceView(const LayerTransition* deviceTransitions, + const CellTopology* deviceCells, + const Range* deviceCellsByFirstTransitionIndex, + const Id* deviceCellsByFirstTransition) const + { + return View{deviceTransitions, + deviceCells, + deviceCellsByFirstTransitionIndex, + deviceCellsByFirstTransition, + mNTransitions, + mNCells, + mNCellsByFirstTransition}; + } + + const auto& getTransitions() const noexcept { return mTransitions; } + const auto& getCells() const noexcept { return mCells; } + const auto& getCellsByFirstTransitionIndex() const noexcept { return mCellsByFirstTransitionIndex; } + const auto& getCellsByFirstTransition() const noexcept { return mCellsByFirstTransition; } + Id getNTransitions() const noexcept { return mNTransitions; } + Id getNCells() const noexcept { return mNCells; } + Id getNCellsByFirstTransition() const noexcept { return mNCellsByFirstTransition; } + + private: + void clear() + { + mNTransitions = 0; + mNCells = 0; + mNCellsByFirstTransition = 0; + mTransitions.fill({}); + mCells.fill({}); + mCellsByFirstTransitionIndex.fill(Range{0, 0}); + mCellsByFirstTransition.fill(0); + } + + void fillCellsByTransition() + { + std::array counts{}; + for (Id cellId = 0; cellId < mNCells; ++cellId) { + ++counts[mCells[cellId].firstTransition]; + } + + Id offset = 0; + for (Id transitionId = 0; transitionId < mNTransitions; ++transitionId) { + mCellsByFirstTransitionIndex[transitionId].setFirstEntry(offset); + mCellsByFirstTransitionIndex[transitionId].setEntries(counts[transitionId]); + offset += counts[transitionId]; + } + + std::array cursor{}; + for (Id cellId = 0; cellId < mNCells; ++cellId) { + const Id transitionId = mCells[cellId].firstTransition; + mCellsByFirstTransition[mCellsByFirstTransitionIndex[transitionId].getFirstEntry() + cursor[transitionId]++] = cellId; + } + mNCellsByFirstTransition = offset; + } + + int mMaxLayers{0}; + int mMaxHoles{0}; + Mask mHoleLayerMask{0}; + Id mNTransitions{0}; + Id mNCells{0}; + Id mNCellsByFirstTransition{0}; + std::array mTransitions{}; + std::array mCells{}; + std::array mCellsByFirstTransitionIndex{}; + std::array mCellsByFirstTransition{}; +}; + +} // namespace o2::its + +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracklet.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracklet.h index 92984c9755ed4..829fe9fa984e4 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracklet.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracklet.h @@ -1,4 +1,4 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. // See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. // All rights not expressly granted are reserved. // @@ -13,130 +13,62 @@ /// \brief /// -#ifndef TRACKINGITSU_INCLUDE_TRACKLET_H_ -#define TRACKINGITSU_INCLUDE_TRACKLET_H_ +#ifndef TRACKINGITS_INCLUDE_TRACKLET_H_ +#define TRACKINGITS_INCLUDE_TRACKLET_H_ +#include "ITStracking/Constants.h" +#include "DataFormatsITS/TimeEstBC.h" #include "ITStracking/Cluster.h" -#include +#include "GPUCommonRtypes.h" #include "GPUCommonMath.h" #include "GPUCommonDef.h" +#include "GPUCommonLogger.h" -#ifndef GPUCA_GPUCODE_DEVICE -#include -#endif - -namespace o2 -{ -namespace its +namespace o2::its { +// tracklets are entirely determined by their two cluster idx struct Tracklet final { - GPUhdi() Tracklet(); - GPUhdi() Tracklet(const int, const int, const Cluster&, const Cluster&, short rof0, short rof1); - GPUhdi() Tracklet(const int, const int, float tanL, float phi, short rof0, short rof1); - GPUhdi() bool operator==(const Tracklet&) const; - GPUhdi() bool operator!=(const Tracklet&) const; - GPUhdi() unsigned char isEmpty() const + GPUhdDefault() Tracklet() = default; + GPUhdi() Tracklet(const int firstClusterOrderingIndex, const int secondClusterOrderingIndex, + const Cluster& firstCluster, const Cluster& secondCluster, const TimeEstBC& t) + : firstClusterIndex(firstClusterOrderingIndex), + secondClusterIndex(secondClusterOrderingIndex), + tanLambda((firstCluster.zCoordinate - secondCluster.zCoordinate) / (firstCluster.radius - secondCluster.radius)), + phi(o2::gpu::GPUCommonMath::ATan2(firstCluster.yCoordinate - secondCluster.yCoordinate, firstCluster.xCoordinate - secondCluster.xCoordinate)), + mTime(t) {} + + GPUhdi() Tracklet(const int idx0, const int idx1, float tanL, float phi, const TimeEstBC& t) + : firstClusterIndex(idx0), + secondClusterIndex(idx1), + tanLambda(tanL), + phi(phi), + mTime(t) {} + GPUhdi() bool operator<(const Tracklet& o) const noexcept { - return firstClusterIndex < 0 || secondClusterIndex < 0; + return (firstClusterIndex != o.firstClusterIndex) ? firstClusterIndex < o.firstClusterIndex : secondClusterIndex < o.secondClusterIndex; } - GPUhdi() auto getDeltaRof() const { return rof[1] - rof[0]; } - GPUhdi() void dump(); - GPUhdi() void dump() const; - GPUhdi() void dump(const int, const int); - GPUhdi() void dump(const int, const int) const; - GPUhdi() unsigned char operator<(const Tracklet&) const; -#ifndef GPUCA_GPUCODE_DEVICE - std::string asString() const + GPUhdi() bool operator==(const Tracklet& o) const noexcept { - return "fClIdx: " + std::to_string(firstClusterIndex) + " sClIdx: " + std::to_string(secondClusterIndex) + - " rof1: " + std::to_string(rof[0]) + " rof2: " + std::to_string(rof[1]) + " delta: " + std::to_string(getDeltaRof()); + return firstClusterIndex == o.firstClusterIndex && secondClusterIndex == o.secondClusterIndex; } -#endif - - int firstClusterIndex; - int secondClusterIndex; - float tanLambda; - float phi; - short rof[2]; -}; - -GPUhdi() Tracklet::Tracklet() : firstClusterIndex{-1}, secondClusterIndex{-1}, tanLambda{0.0f}, phi{0.0f} -{ - rof[0] = -1; - rof[1] = -1; -} - -GPUhdi() Tracklet::Tracklet(const int firstClusterOrderingIndex, const int secondClusterOrderingIndex, - const Cluster& firstCluster, const Cluster& secondCluster, short rof0 = -1, short rof1 = -1) - : firstClusterIndex{firstClusterOrderingIndex}, - secondClusterIndex{secondClusterOrderingIndex}, - tanLambda{(firstCluster.zCoordinate - secondCluster.zCoordinate) / - (firstCluster.radius - secondCluster.radius)}, - phi{o2::gpu::GPUCommonMath::ATan2(firstCluster.yCoordinate - secondCluster.yCoordinate, - firstCluster.xCoordinate - secondCluster.xCoordinate)}, - rof{static_cast(rof0), static_cast(rof1)} -{ - // Nothing to do -} - -GPUhdi() Tracklet::Tracklet(const int idx0, const int idx1, float tanL, float phi, short rof0, short rof1) - : firstClusterIndex{idx0}, - secondClusterIndex{idx1}, - tanLambda{tanL}, - phi{phi}, - rof{static_cast(rof0), static_cast(rof1)} -{ - // Nothing to do -} - -GPUhdi() bool Tracklet::operator==(const Tracklet& rhs) const -{ - return this->firstClusterIndex == rhs.firstClusterIndex && - this->secondClusterIndex == rhs.secondClusterIndex && - this->tanLambda == rhs.tanLambda && - this->phi == rhs.phi && - this->rof[0] == rhs.rof[0] && - this->rof[1] == rhs.rof[1]; -} - -GPUhdi() bool Tracklet::operator!=(const Tracklet& rhs) const -{ - return this->firstClusterIndex != rhs.firstClusterIndex || - this->secondClusterIndex != rhs.secondClusterIndex || - this->tanLambda != rhs.tanLambda || - this->phi != rhs.phi; -} - -GPUhdi() unsigned char Tracklet::operator<(const Tracklet& t) const -{ - if (isEmpty()) { - return false; + GPUhdi() bool isCompatible(const Tracklet& o) const { return mTime.isCompatible(o.mTime); } + GPUhd() void print() const + { + LOGP(info, "TRKLT: fClIdx:{} sClIdx:{} ts:{}+/-{} TgL={} Phi={}", firstClusterIndex, secondClusterIndex, mTime.getTimeStamp(), mTime.getTimeStampError(), tanLambda, phi); } - return true; -} - -GPUhdi() void Tracklet::dump(const int offsetFirst, const int offsetSecond) -{ - printf("fClIdx: %d sClIdx: %d rof1: %hu rof2: %hu\n", firstClusterIndex + offsetFirst, secondClusterIndex + offsetSecond, rof[0], rof[1]); -} - -GPUhdi() void Tracklet::dump(const int offsetFirst, const int offsetSecond) const -{ - printf("fClIdx: %d sClIdx: %d rof1: %hu rof2: %hu\n", firstClusterIndex + offsetFirst, secondClusterIndex + offsetSecond, rof[0], rof[1]); -} + GPUhd() auto& getTimeStamp() noexcept { return mTime; } + GPUhd() const auto& getTimeStamp() const noexcept { return mTime; } -GPUhdi() void Tracklet::dump() -{ - printf("fClIdx: %d sClIdx: %d rof1: %hu rof2: %hu\n", firstClusterIndex, secondClusterIndex, rof[0], rof[1]); -} + int firstClusterIndex{constants::UnusedIndex}; + int secondClusterIndex{constants::UnusedIndex}; + float tanLambda{constants::UnsetValue}; + float phi{constants::UnsetValue}; + TimeEstBC mTime; -GPUhdi() void Tracklet::dump() const -{ - printf("fClIdx: %d sClIdx: %d rof1: %hu rof2: %hu\n", firstClusterIndex, secondClusterIndex, rof[0], rof[1]); -} + ClassDefNV(Tracklet, 1); +}; -} // namespace its -} // namespace o2 +} // namespace o2::its -#endif /* TRACKINGITSU_INCLUDE_TRACKLET_H_ */ +#endif /* TRACKINGITS_INCLUDE_TRACKLET_H_ */ diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Vertexer.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Vertexer.h index ac0cf51921176..eff91e820c56d 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Vertexer.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Vertexer.h @@ -21,158 +21,108 @@ #include #include #include +#include +#include + +#include -#include "ITStracking/ROframe.h" #include "ITStracking/Constants.h" #include "ITStracking/Configuration.h" #include "ITStracking/TimeFrame.h" #include "ITStracking/VertexerTraits.h" -#include "ReconstructionDataFormats/Vertex.h" - -#include "ITStracking/ClusterLines.h" -#include "ITStracking/Tracklet.h" -#include "ITStracking/Cluster.h" - -#include "GPUCommonLogger.h" +#include "ITStracking/BoundedAllocator.h" -class TTree; - -namespace o2 -{ -namespace its +namespace o2::its { -using TimeFrame = o2::its::TimeFrame; -using Vertex = o2::dataformats::Vertex>; +template class Vertexer { + using TimeFrameN = TimeFrame; + using VertexerTraitsN = VertexerTraits; + using LogFunc = std::function; + public: - Vertexer(VertexerTraits* traits); + Vertexer(VertexerTraitsN* traits); virtual ~Vertexer() = default; Vertexer(const Vertexer&) = delete; Vertexer& operator=(const Vertexer&) = delete; - void adoptTimeFrame(TimeFrame& tf); - std::vector& getVertParameters() const; - void setParameters(std::vector& vertParams); - void getGlobalConfiguration(); - - std::vector exportVertices(); - VertexerTraits* getTraits() const { return mTraits; }; + void adoptTimeFrame(TimeFrameN& tf); + auto& getVertParameters() const { return mTraits->getVertexingParameters(); } + void setParameters(const std::vector& vertParams) { mVertParams = vertParams; } + const auto& getParameters() const noexcept { return mVertParams; } + void setMemoryPool(std::shared_ptr pool) { mMemoryPool = pool; } - float clustersToVertices(std::function = [](std::string s) { std::cout << s << std::endl; }); - float clustersToVerticesHybrid(std::function = [](std::string s) { std::cout << s << std::endl; }); + float clustersToVertices(LogFunc = [](const std::string& s) { std::cout << s << '\n'; }); void filterMCTracklets(); + void printSummary() const; template - void findTracklets(T&&... args); - template - void findTrackletsHybrid(T&&... args); - - void findTrivialMCTracklets(); - template - void validateTracklets(T&&... args); - template - void validateTrackletsHybrid(T&&... args); + void findTracklets(T&&... args) + { + mTraits->computeTracklets(std::forward(args)...); + } template - void findVertices(T&&... args); + void validateTracklets(T&&... args) + { + mTraits->computeTrackletMatching(std::forward(args)...); + } template - void findVerticesHybrid(T&&... args); - void findHistVertices(); + void findVertices(T&&... args) + { + mTraits->computeVertices(std::forward(args)...); + } + + void addTruthSeeds() { mTraits->addTruthSeedingVertices(); } template - void initialiseVertexer(T&&... args); + void initialiseVertexer(T&&... args) + { + mTraits->initialise(std::forward(args)...); + } template void initialiseTimeFrame(T&&... args); - template - void initialiseVertexerHybrid(T&&... args); - template - void initialiseTimeFrameHybrid(T&&... args); + + void sortVertices(); // Utils - void dumpTraits(); template - float evaluateTask(void (Vertexer::*)(T...), const char*, std::function logger, T&&... args); - void printEpilog(std::function logger, - bool isHybrid, - const unsigned int trackletN01, const unsigned int trackletN12, const unsigned selectedN, const unsigned int vertexN, - const float initT, const float trackletT, const float selecT, const float vertexT); + float evaluateTask(void (Vertexer::*task)(T...), std::string_view taskName, int iteration, LogFunc& logger, T&&... args); + + void printEpilog(LogFunc& logger, + unsigned int trackletN01, unsigned int trackletN12, + unsigned selectedN, unsigned int vertexN, unsigned int totalVertexN, + float initT, float trackletT, float selecT, float vertexT); + + void setNThreads(int n, std::shared_ptr& arena) { mTraits->setNThreads(n, arena); } private: std::uint32_t mTimeFrameCounter = 0; - VertexerTraits* mTraits = nullptr; /// Observer pointer, not owned by this class - TimeFrame* mTimeFrame = nullptr; /// Observer pointer, not owned by this class + VertexerTraitsN* mTraits = nullptr; /// Observer pointer, not owned by this class + TimeFrameN* mTimeFrame = nullptr; /// Observer pointer, not owned by this class std::vector mVertParams; + std::shared_ptr mMemoryPool; + + enum Steps { + Init = 0, + Trackleting, + Selection, + Finding, + TruthSeeding, + NSteps, + }; + Steps mCurStep{Init}; + static constexpr std::array StateNames{"Initialisation", "Tracklet finding", "Tracklet selection", "Vertex finding", "Truth seeding"}; + std::vector> mTimingStats; + void addTimingStatCurStep(int iteration, double timeMs); }; +template template -void Vertexer::initialiseVertexer(T&&... args) -{ - mTraits->initialise(std::forward(args)...); -} - -template -void Vertexer::findTracklets(T&&... args) -{ - mTraits->computeTracklets(std::forward(args)...); -} - -inline std::vector& Vertexer::getVertParameters() const -{ - return mTraits->getVertexingParameters(); -} - -inline void Vertexer::setParameters(std::vector& vertParams) -{ - mVertParams = vertParams; -} - -inline void Vertexer::dumpTraits() -{ - mTraits->dumpVertexerTraits(); -} - -template -inline void Vertexer::validateTracklets(T&&... args) -{ - mTraits->computeTrackletMatching(std::forward(args)...); -} - -template -inline void Vertexer::findVertices(T&&... args) -{ - mTraits->computeVertices(std::forward(args)...); -} - -template -void Vertexer::initialiseVertexerHybrid(T&&... args) -{ - mTraits->initialiseHybrid(std::forward(args)...); -} - -template -void Vertexer::findTrackletsHybrid(T&&... args) -{ - mTraits->computeTrackletsHybrid(std::forward(args)...); -} - -template -inline void Vertexer::validateTrackletsHybrid(T&&... args) -{ - mTraits->computeTrackletMatchingHybrid(std::forward(args)...); -} - -template -inline void Vertexer::findVerticesHybrid(T&&... args) -{ - mTraits->computeVerticesHybrid(std::forward(args)...); -} - -template -float Vertexer::evaluateTask(void (Vertexer::*task)(T...), const char* taskName, std::function logger, - T&&... args) +float Vertexer::evaluateTask(void (Vertexer::*task)(T...), std::string_view taskName, int iteration, LogFunc& logger, T&&... args) { float diff{0.f}; @@ -185,19 +135,33 @@ float Vertexer::evaluateTask(void (Vertexer::*task)(T...), const char* taskName, diff = diff_t.count(); std::stringstream sstream; - if (taskName == nullptr) { + if (taskName.empty()) { sstream << diff << "\t"; } else { sstream << std::setw(2) << " - " << taskName << " completed in: " << diff << " ms"; } logger(sstream.str()); + + if (mVertParams[iteration].SaveTimeBenchmarks) { + std::string taskNameStr(taskName); + std::transform(taskNameStr.begin(), taskNameStr.end(), taskNameStr.begin(), + [](unsigned char c) { return std::tolower(c); }); + std::replace(taskNameStr.begin(), taskNameStr.end(), ' ', '_'); + if (std::ofstream file{"its_time_benchmarks.txt", std::ios::app}) { + file << "vtx:" << iteration << '\t' << taskNameStr << '\t' << diff << '\n'; + } + addTimingStatCurStep(iteration, diff); + } } else { (this->*task)(std::forward(args)...); } + if (mVertParams[iteration].PrintMemory) { + LOGP(info, "iter:{}:{}: {}", iteration, StateNames[mCurStep], mMemoryPool->asString()); + } + return diff; } -} // namespace its -} // namespace o2 +} // namespace o2::its #endif diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/VertexerTraits.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/VertexerTraits.h index e27d74093aaca..daf8d708e1e23 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/VertexerTraits.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/VertexerTraits.h @@ -17,9 +17,11 @@ #define O2_ITS_TRACKING_VERTEXER_TRAITS_H_ #include +#include #include #include +#include "ITStracking/BoundedAllocator.h" #include "ITStracking/Cluster.h" #include "ITStracking/ClusterLines.h" #include "ITStracking/Configuration.h" @@ -27,149 +29,88 @@ #include "ITStracking/IndexTableUtils.h" #include "ITStracking/TimeFrame.h" #include "ITStracking/Tracklet.h" +#include "ITStracking/MathUtils.h" #include "GPUCommonDef.h" #include "GPUCommonMath.h" +#include + namespace o2 { class MCCompLabel; namespace its { -class ROframe; -using constants::its::LayersNumberVertexer; - -enum class TrackletMode { - Layer0Layer1 = 0, - Layer1Layer2 = 2 -}; +template class VertexerTraits { + using IndexTableUtilsN = IndexTableUtils; + using TimeFrameN = TimeFrame; + public: VertexerTraits() = default; virtual ~VertexerTraits() = default; - GPUhd() static constexpr int4 getEmptyBinsRect() - { - return int4{0, 0, 0, 0}; - } - 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 initialise(const TrackingParameters& trackingParams, const int iteration = 0); - virtual void computeTracklets(const int iteration = 0); - virtual void computeTrackletMatching(const int iteration = 0); - virtual void computeVertices(const int iteration = 0); - virtual void adoptTimeFrame(TimeFrame* tf); - virtual void updateVertexingParameters(const std::vector& vrtPar, const TimeFrameGPUParameters& gpuTfPar); - // Hybrid - virtual void initialiseHybrid(const TrackingParameters& trackingParams, const int iteration = 0) { initialise(trackingParams, iteration); }; - virtual void computeTrackletsHybrid(const int iteration = 0) { computeTracklets(iteration); }; - virtual void computeTrackletMatchingHybrid(const int iteration = 0) { computeTrackletMatching(iteration); }; - virtual void computeVerticesHybrid(const int iteration = 0) { computeVertices(iteration); }; - virtual void adoptTimeFrameHybrid(TimeFrame* tf) { adoptTimeFrame(tf); }; - - void computeVerticesInRof(int, - gsl::span&, - std::vector&, - std::vector&, - std::array&, - std::vector&, - std::vector&, - TimeFrame*, - std::vector*, - const int iteration = 0); - - static const std::vector> selectClusters(const int* indexTable, - const std::array& selectedBinsRect, - const IndexTableUtils& utils); + virtual void initialise(const TrackingParameters& trackingParams); + virtual void computeTracklets(const int iteration); + virtual void computeTrackletMatching(const int iteration); + virtual void computeVertices(const int iteration); + virtual void adoptTimeFrame(TimeFrameN* tf) noexcept { mTimeFrame = tf; } + virtual void updateVertexingParameters(const std::vector& vrtPar); + + // truth tracking + void addTruthSeedingVertices(); // utils - std::vector& getVertexingParameters() { return mVrtParams; } - std::vector getVertexingParameters() const { return mVrtParams; } - void setIsGPU(const unsigned char isgpu) { mIsGPU = isgpu; }; + auto& getVertexingParameters() { return mVrtParams; } + auto getVertexingParameters() const { return mVrtParams; } void setVertexingParameters(std::vector& vertParams) { mVrtParams = vertParams; } - unsigned char getIsGPU() const { return mIsGPU; }; - void dumpVertexerTraits(); - void setNThreads(int n); - int getNThreads() const { return mNThreads; } - - template - static std::pair computeMain(const std::vector& elements) + void setNThreads(int n, std::shared_ptr& arena); + int getNThreads() { return mTaskArena->max_concurrency(); } + virtual bool isGPU() const noexcept { return false; } + virtual const char* getName() const noexcept { return "CPU"; } + virtual bool usesMemoryPool() const noexcept { return true; } + void setMemoryPool(std::shared_ptr pool) { mMemoryPool = pool; } + + static VertexLabel computeMain(const bounded_vector& elements) { - T elem; + // we only care about the source&event of the tracks, not the trackId + auto composeVtxLabel = [](const o2::MCCompLabel& lbl) -> o2::MCCompLabel { + return {o2::MCCompLabel::maxTrackID(), lbl.getEventID(), lbl.getSourceID(), lbl.isFake()}; + }; + std::unordered_map frequency; + for (const auto& element : elements) { + ++frequency[composeVtxLabel(element)]; + } + o2::MCCompLabel elem{}; size_t maxCount = 0; - for (auto& element : elements) { - size_t count = std::count(elements.begin(), elements.end(), element); + for (const auto& [key, count] : frequency) { if (count > maxCount) { maxCount = count; - elem = element; + elem = key; } } - return std::make_pair(elem, static_cast(maxCount) / elements.size()); + if (maxCount <= 1) { // need >50% + elem.setFakeFlag(); + } + return std::make_pair(elem, static_cast(maxCount) / static_cast(elements.size())); } protected: - unsigned char mIsGPU; - int mNThreads = 1; - std::vector mVrtParams; - IndexTableUtils mIndexTableUtils; + IndexTableUtilsN mIndexTableUtils; // Frame related quantities - TimeFrame* mTimeFrame = nullptr; -}; + TimeFrameN* mTimeFrame = nullptr; // observer ptr + private: + bool skipROF(int iteration, int rof) const; -inline void VertexerTraits::initialise(const TrackingParameters& trackingParams, const int iteration) -{ - mTimeFrame->initialise(0, trackingParams, 3, (bool)(!iteration)); // iteration for initialisation must be 0 for correctly resetting the frame, we need to pass the non-reset flag for vertices as well, tho. - setIsGPU(false); -} - -GPUhdi() const int2 VertexerTraits::getPhiBins(float phi, float 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 IndexTableUtils& utils) -{ - const float zRangeMin = directionZIntersection - 2 * maxdeltaz; - const float phiRangeMin = currentCluster.phi - maxdeltaphi; - const float zRangeMax = directionZIntersection + 2 * maxdeltaz; - const float phiRangeMax = currentCluster.phi + maxdeltaphi; - - if (zRangeMax < -utils.getLayerZ(layerIndex + 1) || - zRangeMin > utils.getLayerZ(layerIndex + 1) || zRangeMin > zRangeMax) { - return getEmptyBinsRect(); - } - - 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); -} - -inline void VertexerTraits::adoptTimeFrame(TimeFrame* tf) { mTimeFrame = tf; } + std::shared_ptr mMemoryPool; + std::shared_ptr mTaskArena; +}; } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/json.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/json.h deleted file mode 100644 index d1d246b329907..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/json.h +++ /dev/null @@ -1,16313 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/* - __ _____ _____ _____ - __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.1.2 -|_____|_____|_____|_|___| https://github.com/nlohmann/json - -Licensed under the MIT License . -Copyright (c) 2013-2018 Niels Lohmann . - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#ifndef NLOHMANN_JSON_HPP -#define NLOHMANN_JSON_HPP - -#define NLOHMANN_JSON_VERSION_MAJOR 3 -#define NLOHMANN_JSON_VERSION_MINOR 1 -#define NLOHMANN_JSON_VERSION_PATCH 2 - -#include // all_of, find, for_each -#include // assert -#include // and, not, or -#include // nullptr_t, ptrdiff_t, size_t -#include // hash, less -#include // initializer_list -#include // istream, ostream -#include // iterator_traits, random_access_iterator_tag -#include // accumulate -#include // string, stoi, to_string -#include // declval, forward, move, pair, swap - -// #include -#ifndef NLOHMANN_JSON_FWD_HPP -#define NLOHMANN_JSON_FWD_HPP - -#include // int64_t, uint64_t -#include // map -#include // allocator -#include // string -#include // vector - -/*! -@brief namespace for Niels Lohmann -@see https://github.com/nlohmann -@since version 1.0.0 -*/ -namespace nlohmann -{ -/*! -@brief default JSONSerializer template argument - -This serializer ignores the template arguments and uses ADL -([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) -for serialization. -*/ -template -struct adl_serializer; - -template