diff --git a/.gitignore b/.gitignore index 43c694310ebec2a7a87f52c645ea16d1feec7c28..ce66b6b9f0bb6191bfc40929b521f9e067e1c040 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,6 @@ __pycache__/ # ROOT file *.root +*.sif +**old +install/* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 966af4005239f58a34be7237bb79357c29ccb1f8..9c9515f7b228738620816e34dbd9dbe2bf269614 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,5 @@ variables: - EIC_TAG: "2.5-stable" + EIC_TAG: "2.6-stable" default: image: eicweb.phy.anl.gov:4567/containers/image_recipes/ubuntu_dind:latest @@ -29,6 +29,10 @@ env: fi - echo "CI JUGGLER_TAG for this pipeline set to ${JUGGLER_TAG}" - echo "JUGGLER_TAG=$JUGGLER_TAG" >> juggler.env + - | + if [ "${DETECTOR_TAG}" ]; then + echo "DETECTOR_TAG=$DETECTOR_TAG" >> juggler.env + fi artifacts: reports: dotenv: juggler.env diff --git a/JugBase/CMakeLists.txt b/JugBase/CMakeLists.txt index 965766bc1f7462c2b82030c7bdbff11c7447dacd..f199ed02d8629cf60f649d903bfe710da52297f9 100644 --- a/JugBase/CMakeLists.txt +++ b/JugBase/CMakeLists.txt @@ -21,6 +21,10 @@ gaudi_depends_on_subdirs(GaudiAlg GaudiKernel) gaudi_add_library(JugBase src/*.cpp + src/Utilities/*.cpp + src/Plugins/BFieldOptions.cpp + #src/Plugins/BFieldScalor.cpp + src/Plugins/BFieldUtils.cpp INCLUDE_DIRS EICD PODIO ROOT $ENV{HOME}/stow/podio/include LINK_LIBRARIES GaudiAlgLib GaudiKernel ROOT DD4hep::DDG4IO PUBLIC_HEADERS JugBase) diff --git a/JugBase/JugBase/BField/BFieldOptions.hpp b/JugBase/JugBase/BField/BFieldOptions.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8e303da275ec51a97b5ba0648776263a3fe9a770 --- /dev/null +++ b/JugBase/JugBase/BField/BFieldOptions.hpp @@ -0,0 +1,67 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2017 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Utilities/detail/AxisFwd.hpp" +#include "Acts/Utilities/detail/GridFwd.hpp" +#include "JugBase/Utilities/OptionsFwd.hpp" + +#include <memory> +#include <tuple> +#include <variant> + +// Forward declarations +namespace Acts { +template <typename G> +struct InterpolatedBFieldMapper; + +template <typename M> +class InterpolatedBFieldMap; + +class ConstantBField; +} // namespace Acts + +namespace Jug { +namespace BField { +class ScalableBField; +} +} // namespace Jug + +using InterpolatedMapper2D = Acts::InterpolatedBFieldMapper< + Acts::detail::Grid<Acts::Vector2, Acts::detail::EquidistantAxis, + Acts::detail::EquidistantAxis>>; + +using InterpolatedMapper3D = Acts::InterpolatedBFieldMapper<Acts::detail::Grid< + Acts::Vector3, Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis, + Acts::detail::EquidistantAxis>>; + +using InterpolatedBFieldMap2D = + Acts::InterpolatedBFieldMap<InterpolatedMapper2D>; +using InterpolatedBFieldMap3D = + Acts::InterpolatedBFieldMap<InterpolatedMapper3D>; + +namespace Jug { + +namespace Options { + +using BFieldVariant = + std::variant<std::shared_ptr<InterpolatedBFieldMap2D>, + std::shared_ptr<InterpolatedBFieldMap3D>, + std::shared_ptr<Acts::ConstantBField>, + std::shared_ptr<Jug::BField::ScalableBField>>; + +// common bfield options, with a bf prefix +void addBFieldOptions(boost::program_options::options_description& opt); + +// create the bfield maps +BFieldVariant readBField(const boost::program_options::variables_map& vm); + +} // namespace Options +} // namespace Jug diff --git a/JugBase/JugBase/BField/BFieldScalor.hpp b/JugBase/JugBase/BField/BFieldScalor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..90462d1990d87fb17d4bbb9abd4f120ca4e369b4 --- /dev/null +++ b/JugBase/JugBase/BField/BFieldScalor.hpp @@ -0,0 +1,66 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2019 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Utilities/Logger.hpp" +#include "Jug/Framework/AlgorithmContext.hpp" +#include "Jug/Framework/IContextDecorator.hpp" + +#include <vector> + +namespace Jug { + +namespace BField { + +/// A mockup service that rotates a +/// cylindrical geometry +class BFieldScalor : public IContextDecorator { + public: + /// @brief nested configuration struct + struct Config { + /// Incremental scaling + double scalor = 1.2; + }; + + /// Constructor + /// + /// @param cfg Configuration struct + /// @param logger The logging framework + BFieldScalor(const Config& cfg, + std::unique_ptr<const Acts::Logger> logger = + Acts::getDefaultLogger("BFieldScalor", Acts::Logging::INFO)); + + /// Virtual destructor + virtual ~BFieldScalor() = default; + + /// @brief decorates (adds, modifies) the AlgorithmContext + /// with a geometric rotation per event + /// + /// @note If decorators depend on each other, they have to be + /// added in order. + /// + /// @param context the bare (or at least non-const) Event context + ProcessCode decorate(AlgorithmContext& context) final override; + + /// @brief decorator name() for screen output + const std::string& name() const final override { return m_name; } + + private: + Config m_cfg; ///< the configuration class + std::unique_ptr<const Acts::Logger> m_logger; ///!< the logging instance + std::string m_name = "BFieldScalor"; + + /// Private access to the logging instance + const Acts::Logger& logger() const { return *m_logger; } +}; +} // namespace BField + +} // namespace Jug diff --git a/JugBase/JugBase/BField/BFieldUtils.hpp b/JugBase/JugBase/BField/BFieldUtils.hpp new file mode 100644 index 0000000000000000000000000000000000000000..48376e8df4384c76f2b41c192bcd69c850d87f3b --- /dev/null +++ b/JugBase/JugBase/BField/BFieldUtils.hpp @@ -0,0 +1,225 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2017 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include "Acts/Definitions/Units.hpp" +#include "Acts/MagneticField/InterpolatedBFieldMap.hpp" +#include "Acts/Utilities/Logger.hpp" +#include "Acts/Utilities/detail/Axis.hpp" +#include "Acts/Utilities/detail/Grid.hpp" + +namespace Jug { + +namespace BField { + +namespace txt { +/// Method to setup the FieldMapper +/// @param localToGlobalBin Function mapping the local bins of r,z to the +/// global +/// bin of the map magnetic field value e.g.: we have small grid with the +/// values: r={2,3}, z ={4,5}, the corresponding indices are i(r) and j(z), +/// the +/// globalIndex is M and the field map is: +///|| r | i || z | j || |B(r,z)| || M || +/// ----------------------------------- +///|| 2 | 0 || 4 | 0 || 2.323 || 0 || +///|| 2 | 0 || 5 | 1 || 2.334 || 1 || +///|| 3 | 1 || 4 | 0 || 2.325 || 2 || +///|| 3 | 1 || 5 | 1 || 2.331 || 3 || +/// +/// @code +/// In this case the function would look like: +/// [](std::array<size_t, 2> binsRZ, std::array<size_t, 2> nBinsRZ) { +/// return (binsRZ.at(0) * nBinsRZ.at(1) + binsRZ.at(1)); +/// } +/// @endcode +/// @param[in] fieldMapFile Path to file containing field map in txt format +/// @param[in] lengthUnit The unit of the grid points +/// @param[in] BFieldUnit The unit of the magnetic field +/// @param[in] nPoints Extimate of number of grid points in field map needed +/// for allocation +/// @note This information is only used as a hint for the required size of +/// the internal vectors. A correct value is not needed, but will help +/// to speed up the field map initialization process. +/// @param[in] firstOctant Flag if set to true indicating that only the +/// first +/// quadrant of the grid points and the BField values has been given and +/// that +/// the BFieldMap should be created symmetrically for all quadrants. +/// e.g. we have the grid values r={0,1} with BFieldValues={2,3} on the r +/// axis. +/// If the flag is set to true the r-axis grid values will be set to +/// {-1,0,1} +/// and the BFieldValues will be set to {3,2,3}. +Acts::InterpolatedBFieldMapper< + Acts::detail::Grid<Acts::Vector2, Acts::detail::EquidistantAxis, + Acts::detail::EquidistantAxis>> +fieldMapperRZ(std::function<size_t(std::array<size_t, 2> binsRZ, + std::array<size_t, 2> nBinsRZ)> + localToGlobalBin, + std::string fieldMapFile = "", + double lengthUnit = Acts::UnitConstants::mm, + double BFieldUnit = Acts::UnitConstants::T, size_t nPoints = 1000, + bool firstOctant = false); + +/// Method to setup the FieldMapper +/// @param localToGlobalBin Function mapping the local bins of x,y,z to the +/// global bin of the map magnetic field value e.g.: we have small grid with +/// the +/// values: x={2,3}, y={3,4}, z ={4,5}, the corresponding indices are i(x), +/// j(y) +/// and z(k), the globalIndex is M and the field map is: +///|| x | i || y | j || z | k || |B(x,y,z)| || M || +/// -------------------------------------------- +///|| 2 | 0 || 3 | 0 || 4 | 0 || 2.323 || 0 || +///|| 2 | 0 || 3 | 0 || 5 | 1 || 2.334 || 1 || +///|| 2 | 0 || 4 | 1 || 4 | 0 || 2.325 || 2 || +///|| 2 | 0 || 4 | 1 || 5 | 1 || 2.331 || 3 || +///|| 3 | 1 || 3 | 0 || 4 | 0 || 2.323 || 4 || +///|| 3 | 1 || 3 | 0 || 5 | 1 || 2.334 || 5 || +///|| 3 | 1 || 4 | 1 || 4 | 0 || 2.325 || 6 || +///|| 3 | 1 || 4 | 1 || 5 | 1 || 2.331 || 7 || +/// +/// @code +/// In this case the function would look like: +/// [](std::array<size_t, 3> binsXYZ, std::array<size_t, 3> nBinsXYZ) { +/// return (binsXYZ.at(0) * (nBinsXYZ.at(1) * nBinsXYZ.at(2)) +/// + binsXYZ.at(1) * nBinsXYZ.at(2) +/// + binsXYZ.at(2)); +/// } +/// @endcode +/// @param[in] fieldMapFile Path to file containing field map in txt format +/// @param[in] lengthUnit The unit of the grid points +/// @param[in] BFieldUnit The unit of the magnetic field +/// @param[in] nPoints Extimate of number of grid points in field map needed +/// for allocation +/// @note This information is only used as a hint for the required size of +/// the internal vectors. A correct value is not needed, but will help +/// to speed up the field map initialization process. +/// @param[in] firstOctant Flag if set to true indicating that only the +/// first +/// octant of the grid points and the BField values has been given and that +/// the BFieldMap should be created symmetrically for all quadrants. +/// e.g. we have the grid values z={0,1} with BFieldValues={2,3} on the r +/// axis. +/// If the flag is set to true the z-axis grid values will be set to +/// {-1,0,1} +/// and the BFieldValues will be set to {3,2,3}. +Acts::InterpolatedBFieldMapper<Acts::detail::Grid< + Acts::Vector3, Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis, + Acts::detail::EquidistantAxis>> +fieldMapperXYZ(std::function<size_t(std::array<size_t, 3> binsXYZ, + std::array<size_t, 3> nBinsXYZ)> + localToGlobalBin, + std::string fieldMapFile = "", + double lengthUnit = Acts::UnitConstants::mm, + double BFieldUnit = Acts::UnitConstants::T, + size_t nPoints = 1000, bool firstOctant = false); +} // namespace txt + +namespace root { +/// Method to setup the FieldMapper +/// @param localToGlobalBin Function mapping the local bins of r,z to the +/// global +/// bin of the map magnetic field value e.g.: we have small grid with the +/// values: r={2,3}, z ={4,5}, the corresponding indices are i(r) and j(z), +/// the +/// globalIndex is M and the field map is: +///|| r | i || z | j || |B(r,z)| || M || +/// ----------------------------------- +///|| 2 | 0 || 4 | 0 || 2.323 || 0 || +///|| 2 | 0 || 5 | 1 || 2.334 || 1 || +///|| 3 | 1 || 4 | 0 || 2.325 || 2 || +///|| 3 | 1 || 5 | 1 || 2.331 || 3 || +/// +/// @code +/// In this case the function would look like: +/// [](std::array<size_t, 2> binsRZ, std::array<size_t, 2> nBinsRZ) { +/// return (binsRZ.at(0) * nBinsRZ.at(1) + binsRZ.at(1)); +/// } +/// @endcode +/// @param[in] fieldMapFile Path to file containing field map in txt format +/// @param[in] treeName The name of the root tree +/// @param[in] lengthUnit The unit of the grid points +/// @param[in] BFieldUnit The unit of the magnetic field +/// @param[in] firstQuadrant Flag if set to true indicating that only the +/// first +/// quadrant of the grid points and the BField values has been given and +/// that +/// the BFieldMap should be created symmetrically for all quadrants. +/// e.g. we have the grid values r={0,1} with BFieldValues={2,3} on the r +/// axis. +/// If the flag is set to true the r-axis grid values will be set to +/// {-1,0,1} +/// and the BFieldValues will be set to {3,2,3}. +Acts::InterpolatedBFieldMapper< + Acts::detail::Grid<Acts::Vector2, Acts::detail::EquidistantAxis, + Acts::detail::EquidistantAxis>> +fieldMapperRZ(std::function<size_t(std::array<size_t, 2> binsRZ, + std::array<size_t, 2> nBinsRZ)> + localToGlobalBin, + std::string fieldMapFile = "", std::string treeName = "", + double lengthUnit = Acts::UnitConstants::mm, + double BFieldUnit = Acts::UnitConstants::T, + bool firstOctant = false); + +/// Method to setup the FieldMapper +/// @param localToGlobalBin Function mapping the local bins of x,y,z to the +/// global bin of the map magnetic field value e.g.: we have small grid with +/// the +/// values: x={2,3}, y={3,4}, z ={4,5}, the corresponding indices are i(x), +/// j(y) +/// and z(k), the globalIndex is M and the field map is: +///|| x | i || y | j || z | k || |B(x,y,z)| || M || +/// -------------------------------------------- +///|| 2 | 0 || 3 | 0 || 4 | 0 || 2.323 || 0 || +///|| 2 | 0 || 3 | 0 || 5 | 1 || 2.334 || 1 || +///|| 2 | 0 || 4 | 1 || 4 | 0 || 2.325 || 2 || +///|| 2 | 0 || 4 | 1 || 5 | 1 || 2.331 || 3 || +///|| 3 | 1 || 3 | 0 || 4 | 0 || 2.323 || 4 || +///|| 3 | 1 || 3 | 0 || 5 | 1 || 2.334 || 5 || +///|| 3 | 1 || 4 | 1 || 4 | 0 || 2.325 || 6 || +///|| 3 | 1 || 4 | 1 || 5 | 1 || 2.331 || 7 || +/// +/// @code +/// In this case the function would look like: +/// [](std::array<size_t, 3> binsXYZ, std::array<size_t, 3> nBinsXYZ) { +/// return (binsXYZ.at(0) * (nBinsXYZ.at(1) * nBinsXYZ.at(2)) +/// + binsXYZ.at(1) * nBinsXYZ.at(2) +/// + binsXYZ.at(2)); +/// } +/// @endcode +/// @param[in] fieldMapFile Path to file containing field map in txt format +/// @param[in] treeName The name of the root tree +/// @param[in] lengthUnit The unit of the grid points +/// @param[in] BFieldUnit The unit of the magnetic field +/// @param[in] firstOctant Flag if set to true indicating that only the +/// first +/// octant of the grid points and the BField values has been given and that +/// the BFieldMap should be created symmetrically for all quadrants. +/// e.g. we have the grid values z={0,1} with BFieldValues={2,3} on the r +/// axis. +/// If the flag is set to true the z-axis grid values will be set to +/// {-1,0,1} +/// and the BFieldValues will be set to {3,2,3}. +Acts::InterpolatedBFieldMapper<Acts::detail::Grid< + Acts::Vector3, Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis, + Acts::detail::EquidistantAxis>> +fieldMapperXYZ(std::function<size_t(std::array<size_t, 3> binsXYZ, + std::array<size_t, 3> nBinsXYZ)> + localToGlobalBin, + std::string fieldMapFile = "", std::string treeName = "", + double lengthUnit = Acts::UnitConstants::mm, + double BFieldUnit = Acts::UnitConstants::T, + bool firstOctant = false); +} // namespace root + +} // namespace BField + +} // namespace Jug diff --git a/JugBase/JugBase/BField/ScalableBField.hpp b/JugBase/JugBase/BField/ScalableBField.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8307a5a4c9a3cd9d9c0f53a247db4631064a2898 --- /dev/null +++ b/JugBase/JugBase/BField/ScalableBField.hpp @@ -0,0 +1,137 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2016-2018 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/MagneticField/MagneticFieldContext.hpp" + +namespace Jug { + +namespace BField { + +/// The Context to be handed around +struct ScalableBFieldContext { + double scalor = 1.; +}; + +/// @ingroup MagneticField +/// +/// @brief returns a given constant field value at every point +/// +/// This class is based on the constant magnetic field class +/// but allows a event based context +class ScalableBField final { + public: + struct Cache { + double scalor = 1.; + + /// @brief constructor with context + Cache(const Acts::MagneticFieldContext& mcfg) { + scalor = std::any_cast<const ScalableBFieldContext>(mcfg).scalor; + } + }; + + /// @brief construct constant magnetic field from field vector + /// + /// @param [in] B magnetic field vector in global coordinate system + explicit ScalableBField(Acts::Vector3 B) : m_BField(std::move(B)) {} + + /// @brief construct constant magnetic field from components + /// + /// @param [in] Bx magnetic field component in global x-direction + /// @param [in] By magnetic field component in global y-direction + /// @param [in] Bz magnetic field component in global z-direction + ScalableBField(double Bx = 0., double By = 0., double Bz = 0.) + : m_BField(Bx, By, Bz) {} + + /// @brief retrieve magnetic field value + /// + /// @param [in] position global position + /// @return magnetic field vector + /// + /// @note The @p position is ignored and only kept as argument to provide + /// a consistent interface with other magnetic field services. + Acts::Vector3 getField(const Acts::Vector3& /*position*/) const { + return m_BField; + } + + /// @brief retrieve magnetic field value + /// + /// @param [in] position global position + /// @param [in] cache Cache object (is ignored) + /// @return magnetic field vector + /// + /// @note The @p position is ignored and only kept as argument to provide + /// a consistent interface with other magnetic field services. + Acts::Vector3 getField(const Acts::Vector3& /*position*/, + Cache& cache) const { + return m_BField * cache.scalor; + } + + /// @brief retrieve magnetic field value & its gradient + /// + /// @param [in] position global position + /// @param [out] derivative gradient of magnetic field vector as (3x3) + /// matrix + /// @return magnetic field vector + /// + /// @note The @p position is ignored and only kept as argument to provide + /// a consistent interface with other magnetic field services. + /// @note currently the derivative is not calculated + /// @todo return derivative + Acts::Vector3 getFieldGradient(const Acts::Vector3& /*position*/, + Acts::ActsMatrix<3, 3>& /*derivative*/) const { + return m_BField; + } + + /// @brief retrieve magnetic field value & its gradient + /// + /// @param [in] position global position + /// @param [out] derivative gradient of magnetic field vector as (3x3) + /// matrix + /// @param [in] cache Cache object (is ignored) + /// @return magnetic field vector + /// + /// @note The @p position is ignored and only kept as argument to provide + /// a consistent interface with other magnetic field services. + /// @note currently the derivative is not calculated + /// @todo return derivative + Acts::Vector3 getFieldGradient(const Acts::Vector3& /*position*/, + Acts::ActsMatrix<3, 3>& /*derivative*/, + Cache& cache) const { + return m_BField * cache.scalor; + } + + /// @brief check whether given 3D position is inside look-up domain + /// + /// @param [in] position global 3D position + /// @return @c true if position is inside the defined look-up grid, + /// otherwise @c false + /// @note The method will always return true for the constant B-Field + bool isInside(const Acts::Vector3& /*position*/) const { return true; } + + /// @brief update magnetic field vector from components + /// + /// @param [in] Bx magnetic field component in global x-direction + /// @param [in] By magnetic field component in global y-direction + /// @param [in] Bz magnetic field component in global z-direction + void setField(double Bx, double By, double Bz) { m_BField << Bx, By, Bz; } + + /// @brief update magnetic field vector + /// + /// @param [in] B magnetic field vector in global coordinate system + void setField(const Acts::Vector3& B) { m_BField = B; } + + private: + /// magnetic field vector + Acts::Vector3 m_BField; +}; + +} // namespace BField +} // namespace Jug diff --git a/JugBase/JugBase/Utilities/GroupBy.hpp b/JugBase/JugBase/Utilities/GroupBy.hpp new file mode 100644 index 0000000000000000000000000000000000000000..399e18bf8a8d881420b33a0548df6794591fee9d --- /dev/null +++ b/JugBase/JugBase/Utilities/GroupBy.hpp @@ -0,0 +1,141 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2020 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include "JugBase/Utilities/Range.hpp" + +#include <algorithm> +#include <iterator> +#include <utility> + +namespace Jug { + +/// Proxy for iterating over groups of elements within a container. +/// +/// @note Each group will contain at least one element. +/// +/// Consecutive elements with the same key (as defined by the KeyGetter) are +/// placed in one group. The proxy should always be used as part of a +/// range-based for loop. In combination with structured bindings to reduce the +/// boilerplate, the group iteration can be written as +/// +/// for (auto&& [key, elements] : GroupBy<...>(...)) { +/// // do something with just the key +/// ... +/// +/// // iterate over the group elements +/// for (const auto& element : elements) { +/// ... +/// } +/// } +/// +template <typename Iterator, typename KeyGetter> +class GroupBy { + public: + /// The key type that identifies elements within a group. + using Key = std::decay_t<decltype(KeyGetter()(*Iterator()))>; + /// A Group is an iterator range with the associated key. + using Group = std::pair<Key, Range<Iterator>>; + /// Iterator type representing the end of the groups. + /// + /// The end iterator will not be dereferenced in C++17 range-based loops. It + /// can thus be a simpler type without the overhead of the full group iterator + /// below. + using GroupEndIterator = Iterator; + /// Iterator type representing a group of elements. + class GroupIterator { + public: + using iterator_category = std::input_iterator_tag; + using value_type = Group; + using difference_type = std::ptrdiff_t; + using pointer = Group*; + using reference = Group&; + + constexpr GroupIterator(const GroupBy& groupBy, Iterator groupBegin) + : m_groupBy(groupBy), + m_groupBegin(groupBegin), + m_groupEnd(groupBy.findEndOfGroup(groupBegin)) {} + /// Pre-increment operator to advance to the next group. + constexpr GroupIterator& operator++() { + // make the current end the new group beginning + std::swap(m_groupBegin, m_groupEnd); + // find the end of the next group starting from the new beginning + m_groupEnd = m_groupBy.findEndOfGroup(m_groupBegin); + return *this; + } + /// Post-increment operator to advance to the next group. + constexpr GroupIterator operator++(int) { + GroupIterator retval = *this; + ++(*this); + return retval; + } + /// Derefence operator that returns the pointed-to group of elements. + constexpr Group operator*() const { + const Key key = (m_groupBegin != m_groupEnd) + ? m_groupBy.m_keyGetter(*m_groupBegin) + : Key(); + return {key, makeRange(m_groupBegin, m_groupEnd)}; + } + + private: + const GroupBy& m_groupBy; + Iterator m_groupBegin; + Iterator m_groupEnd; + + friend constexpr bool operator==(const GroupIterator& lhs, + const GroupEndIterator& rhs) { + return lhs.m_groupBegin == rhs; + } + friend constexpr bool operator!=(const GroupIterator& lhs, + const GroupEndIterator& rhs) { + return not(lhs == rhs); + } + }; + + /// Construct the group-by proxy for an iterator range. + constexpr GroupBy(Iterator begin, Iterator end, + KeyGetter keyGetter = KeyGetter()) + : m_begin(begin), m_end(end), m_keyGetter(std::move(keyGetter)) {} + constexpr GroupIterator begin() const { + return GroupIterator(*this, m_begin); + } + constexpr GroupEndIterator end() const { return m_end; } + constexpr bool empty() const { return m_begin == m_end; } + + private: + Iterator m_begin; + Iterator m_end; + KeyGetter m_keyGetter; + + /// Find the end of the group that starts at the given position. + /// + /// This uses a linear search from the start position and thus has linear + /// complexity in the group size. It does not assume any ordering of the + /// underlying container and is a cache-friendly access pattern. + constexpr Iterator findEndOfGroup(Iterator start) const { + // check for end so we can safely dereference the start iterator. + if (start == m_end) { + return start; + } + // search the first element that does not share a key with the start. + return std::find_if_not(std::next(start), m_end, + [this, start](const auto& x) { + return m_keyGetter(x) == m_keyGetter(*start); + }); + } +}; + +/// Construct the group-by proxy for a container. +template <typename Container, typename KeyGetter> +auto makeGroupBy(const Container& container, KeyGetter keyGetter) + -> GroupBy<decltype(std::begin(container)), KeyGetter> { + return {std::begin(container), std::end(container), std::move(keyGetter)}; +} + +} // namespace Jug diff --git a/JugBase/JugBase/Utilities/Helpers.hpp b/JugBase/JugBase/Utilities/Helpers.hpp new file mode 100644 index 0000000000000000000000000000000000000000..890bb25f4adae956c993d93b0bfe3640d20ea566 --- /dev/null +++ b/JugBase/JugBase/Utilities/Helpers.hpp @@ -0,0 +1,126 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2019 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include <string> + +#include "TEfficiency.h" +#include "TFitResult.h" +#include "TFitResultPtr.h" +#include "TH1F.h" +#include "TH2F.h" +#include "TProfile.h" +#include "TROOT.h" + +namespace Jug { + +namespace PlotHelpers { +/// @brief Nested binning struct for booking plots +struct Binning { + Binning(){}; + + Binning(std::string bTitle, int bins, float bMin, float bMax) + : title(bTitle), nBins(bins), min(bMin), max(bMax){}; + + std::string title; ///< title to be displayed + int nBins; ///< number of bins + float min; ///< minimum value + float max; ///< maximum value +}; + +/// @brief book a 1D histogram +/// @param histName the name of histogram +/// @param histTitle the title of histogram +/// @param varBinning the binning info of variable +/// @return histogram pointer +TH1F* bookHisto(const char* histName, const char* histTitle, + const Binning& varBinning); + +/// @brief book a 2D histogram +/// @param histName the name of histogram +/// @param histTitle the title of histogram +/// @param varXBinning the binning info of variable at x axis +/// @param varYBinning the binning info of variable at y axis +/// @return histogram pointer +TH2F* bookHisto(const char* histName, const char* histTitle, + const Binning& varXBinning, const Binning& varYBinning); + +/// @brief fill a 1D histogram +/// @param hist histogram to fill +/// @param value value to fill +/// @param weight weight to fill +void fillHisto(TH1F* hist, float value, float weight = 1.0); + +/// @brief fill a 2D histogram +/// @param hist histogram to fill +/// @param xValue x value to fill +/// @param yValue y value to fill +/// @param weight weight to fill +void fillHisto(TH2F* hist, float xValue, float yValue, float weight = 1.0); + +/// @brief extract details, i.e. mean and width of a 1D histogram and fill +/// them into histograms +/// @param inputHist histogram to investigate +/// @param j which bin number of meanHist and widthHist to fill +/// @param meanHist histogram to fill the mean value of inputHist +/// @param widthHist histogram to fill the width value of inputHist +/// +/// @todo write specialized helper class to extract details of hists +void anaHisto(TH1D* inputHist, int j, TH1F* meanHist, TH1F* widthHist); + +/// @brief book a 1D efficiency plot +/// @param effName the name of plot +/// @param effTitle the title of plot +/// @param varBinning the binning info of variable +/// @return TEfficiency pointer +TEfficiency* bookEff(const char* effName, const char* effTitle, + const Binning& varBinning); + +/// @brief book a 2D efficiency plot +/// @param effName the name of plot +/// @param effTitle the title of plot +/// @param varXBinning the binning info of variable at x axis +/// @param varYBinning the binning info of variable at y axis +/// @return TEfficiency pointer +TEfficiency* bookEff(const char* effName, const char* effTitle, + const Binning& varXBinning, const Binning& varYBinning); + +/// @brief fill a 1D efficiency plot +/// @param efficiency plot to fill +/// @param value value to fill +/// @param status bool to denote passed or not +void fillEff(TEfficiency* efficiency, float value, bool status); + +/// @brief fill a 2D efficiency plot +/// @param efficiency plot to fill +/// @param xValue x value to fill +/// @param yValue y value to fill +/// @param status bool to denote passed or not +void fillEff(TEfficiency* efficiency, float xValue, float yValue, bool status); + +/// @brief book a TProfile plot +/// @param profName the name of plot +/// @param profTitle the title of plot +/// @param varXBinning the binning info of variable at x axis +/// @param varYBinning the binning info of variable at y axis +/// @return TProfile pointer +TProfile* bookProf(const char* profName, const char* profTitle, + const Binning& varXBinning, const Binning& varYBinning); + +/// @brief fill a TProfile plot +/// @param profile plot to fill +/// @param xValue xvalue to fill +/// @param yValue yvalue to fill +/// @param weight weight to fill +void fillProf(TProfile* profile, float xValue, float yValue, + float weight = 1.0); + +} // namespace PlotHelpers + +} // namespace Jug diff --git a/JugBase/JugBase/Utilities/Options.hpp b/JugBase/JugBase/Utilities/Options.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c927f2d37f4a68e0bb2acb5d460d09f6bc8dd6b9 --- /dev/null +++ b/JugBase/JugBase/Utilities/Options.hpp @@ -0,0 +1,170 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2017-2020 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include <array> +#include <iosfwd> +#include <optional> +#include <vector> + +namespace Jug { +namespace Options { + +/// @defgroup option-types Additional types for program options +/// +/// All types are intended as utility type for the user options and not as a +/// variable type for the configuration structs. They should only be used where +/// a single option can not be represented by an existing primitive types. +/// +/// They also must be distinct types and can not just be typedefs; otherwise we +/// can not define the required operator{<<,>>} overloads in this namespace. +/// +/// @{ + +/// Half open [lower,upper) interval type for a single user option. +/// +/// A missing limit represents an unbounded upper or lower limit. With just +/// one defined limit the interval is just a lower/upper bound; with both +/// limits undefined, the interval is unbounded everywhere and thus contains +/// all possible values. +struct Interval { + std::optional<double> lower; + std::optional<double> upper; +}; + +/// A fixed number of real values as one user option. +/// +/// @note Implemented as a subclass so it is distinct from `std::array` +/// and we can provide overloads in the same namespace. +template <size_t kSize> +class Reals : public std::array<double, kSize> {}; + +/// An arbitrary number of revaluesal as one user option. +/// +/// @note Making this a `std::vector<double>` typedef or subclass confuses +/// program options, since `std::vector<double>` is interpreted as a `double` +/// option that can be provided multiple times. +struct VariableReals { + std::vector<double> values; +}; + +/// A fixed number of integers as one user option. +/// +/// @note Implemented as a subclass so it is distinct from `std::array` +/// and we can provide overloads in the same namespace. +template <size_t kSize> +class Integers : public std::array<int, kSize> {}; + +/// An arbitrary number of integers as one user option. +/// +/// @note Making this a `std::vector<int>` typedef or subclass confuses +/// program options, since `std::vector<int>` is interpreted as an `int` +/// option that can be provided multiple times. +struct VariableIntegers { + std::vector<int> values; +}; + +/// @} + +/// Extract an interval from an input of the form 'lower:upper'. +/// +/// An input of the form `lower:` or `:upper` sets just one of the limits. Any +/// other input leads to an unbounded interval. +/// +/// @note The more common range notation uses `lower-upper` but the `-` +/// separator complicates the parsing of negative values. +std::istream& operator>>(std::istream& is, Interval& interval); + +/// Print an interval as `lower:upper`. +std::ostream& operator<<(std::ostream& os, const Interval& interval); + +namespace detail { +void parseDoublesFixed(std::istream& is, size_t size, double* values); +void parseDoublesVariable(std::istream& is, std::vector<double>& values); +void printDoubles(std::ostream& os, size_t size, const double* values); +} // namespace detail + +/// Extract a fixed number of doubles from an input of the form 'x:y:z'. +/// +/// @note If the values would be separated by whitespace, negative values +/// and additional command line both start with `-` and would be +/// undistinguishable. +template <size_t kSize> +inline std::istream& operator>>(std::istream& is, Reals<kSize>& values) { + detail::parseDoublesFixed(is, kSize, values.data()); + return is; +} + +/// Extract a variable number of doubles from an input of the form 'x:y:...'. +/// +/// @note If the values would be separated by whitespace, negative values +/// and additional command line both start with `-` and would be +/// undistinguishable. +inline std::istream& operator>>(std::istream& is, VariableReals& values) { + detail::parseDoublesVariable(is, values.values); + return is; +} + +/// Print a fixed number of doubles as `x:y:z`. +template <size_t kSize> +inline std::ostream& operator<<(std::ostream& os, const Reals<kSize>& values) { + detail::printDoubles(os, kSize, values.data()); + return os; +} + +/// Print a variable number of doubles as `x:y:z:...`. +inline std::ostream& operator<<(std::ostream& os, const VariableReals& values) { + detail::printDoubles(os, values.values.size(), values.values.data()); + return os; +} + +namespace detail { +void parseIntegersFixed(std::istream& is, size_t size, int* values); +void parseIntegersVariable(std::istream& is, std::vector<int>& values); +void printIntegers(std::ostream& os, size_t size, const int* values); +} // namespace detail + +/// Extract a fixed number of integers from an input of the form 'x:y:z'. +/// +/// @note If the values would be separated by whitespace, negative values +/// and additional command line both start with `-` and would be +/// undistinguishable. +template <size_t kSize> +inline std::istream& operator>>(std::istream& is, Integers<kSize>& values) { + detail::parseIntegersFixed(is, kSize, values.data()); + return is; +} + +/// Extract a variable number of integers from an input of the form 'x:y:...'. +/// +/// @note If the values would be separated by whitespace, negative values +/// and additional command line both start with `-` and would be +/// undistinguishable. +inline std::istream& operator>>(std::istream& is, VariableIntegers& values) { + detail::parseIntegersVariable(is, values.values); + return is; +} + +/// Print a fixed number of integers as `x:y:z`. +template <size_t kSize> +inline std::ostream& operator<<(std::ostream& os, + const Integers<kSize>& values) { + detail::printIntegers(os, kSize, values.data()); + return os; +} + +/// Print a variable number of integers as `x:y:z:...`. +inline std::ostream& operator<<(std::ostream& os, + const VariableIntegers& values) { + detail::printIntegers(os, values.values.size(), values.values.data()); + return os; +} + +} // namespace Options +} // namespace Jug diff --git a/JugBase/JugBase/Utilities/OptionsFwd.hpp b/JugBase/JugBase/Utilities/OptionsFwd.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8f03f638979427a366e1e8d98fe32f94bac28cc9 --- /dev/null +++ b/JugBase/JugBase/Utilities/OptionsFwd.hpp @@ -0,0 +1,23 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2019 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +namespace boost { +namespace program_options { +class options_description; +class variables_map; +} // namespace program_options +} // namespace boost + +namespace Jug { +namespace Options { +using Description = ::boost::program_options::options_description; +using Variables = ::boost::program_options::variables_map; +} // namespace Options +} // namespace Jug diff --git a/JugBase/JugBase/Utilities/Paths.hpp b/JugBase/JugBase/Utilities/Paths.hpp new file mode 100644 index 0000000000000000000000000000000000000000..555975100d371ddd6d3dfc13d78be206eeea21f0 --- /dev/null +++ b/JugBase/JugBase/Utilities/Paths.hpp @@ -0,0 +1,46 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2017 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include <string> +#include <utility> +#include <vector> + +namespace Jug { + +/// Ensure that the given directory exists and is writable. +/// +/// @return Canonical path to the directory. +/// +/// Will create missing directories and throw on any error. +std::string ensureWritableDirectory(const std::string& dir); + +/// Join dir and name into one path with correct handling of empty dirs. +std::string joinPaths(const std::string& dir, const std::string& name); + +/// Construct a file path of the form `[<dir>/]event<XXXXXXXXX>-<name>`. +/// +/// @params dir output directory, current directory if empty +/// @params name basic filename +/// @params event event number +std::string perEventFilepath(const std::string& dir, const std::string& name, + size_t event); + +/// Determine the range of available events in a directory of per-event files. +/// +/// @params dir input directory, current directory if empty +/// @params name base filename +/// @return first and last+1 event number +/// @returns {0, 0} when no matching files could be found +/// +/// Event files must be named `[<dir>/]event<XXXXXXXXX>-<name>` to be considered +std::pair<size_t, size_t> determineEventFilesRange(const std::string& dir, + const std::string& name); + +} // namespace Jug diff --git a/JugBase/JugBase/Utilities/Range.hpp b/JugBase/JugBase/Utilities/Range.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0cd3588adeb18d2f1525bf05879c783426e7d756 --- /dev/null +++ b/JugBase/JugBase/Utilities/Range.hpp @@ -0,0 +1,56 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2019 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include <iterator> +#include <utility> + +namespace Jug { + +/// A wrapper around a pair of iterators to simplify range-based loops. +/// +/// Some standard library algorithms return pairs of iterators to identify +/// a sub-range. This wrapper simplifies the iteration and should be used as +/// follows: +/// +/// for (auto x : makeRange(std::equal_range(...)) { +/// ... +/// } +/// +template <typename Iterator> +class Range { + public: + Range(Iterator b, Iterator e) : m_begin(b), m_end(e) {} + Range(Range&&) = default; + Range(const Range&) = default; + ~Range() = default; + Range& operator=(Range&&) = default; + Range& operator=(const Range&) = default; + + Iterator begin() const { return m_begin; } + Iterator end() const { return m_end; } + bool empty() const { return m_begin == m_end; } + std::size_t size() const { return std::distance(m_begin, m_end); } + + private: + Iterator m_begin; + Iterator m_end; +}; + +template <typename Iterator> +Range<Iterator> makeRange(Iterator begin, Iterator end) { + return Range<Iterator>(begin, end); +} + +template <typename Iterator> +Range<Iterator> makeRange(std::pair<Iterator, Iterator> range) { + return Range<Iterator>(range.first, range.second); +} + +} // namespace Jug diff --git a/JugBase/src/Plugins/BFieldOptions.cpp b/JugBase/src/Plugins/BFieldOptions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ca0831427b568434d8205885a4936b3cf504ab4e --- /dev/null +++ b/JugBase/src/Plugins/BFieldOptions.cpp @@ -0,0 +1,228 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2019 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "JugBase/BField/BFieldOptions.hpp" + +#include "Acts/Definitions/Units.hpp" +#include "Acts/MagneticField/ConstantBField.hpp" +#include "Acts/MagneticField/InterpolatedBFieldMap.hpp" +#include "Acts/Utilities/Logger.hpp" +#include "JugBase/BField/BFieldUtils.hpp" +#include "JugBase/BField/ScalableBField.hpp" +#include "JugBase/Utilities/Options.hpp" + +#include <iostream> +#include <tuple> +#include <utility> + +//#include <boost/program_options.hpp> + +//namespace po = boost::program_options; + +using InterpolatedMapper2D = Acts::InterpolatedBFieldMapper< + Acts::detail::Grid<Acts::Vector2, Acts::detail::EquidistantAxis, + Acts::detail::EquidistantAxis>>; + +using InterpolatedMapper3D = Acts::InterpolatedBFieldMapper<Acts::detail::Grid< + Acts::Vector3, Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis, + Acts::detail::EquidistantAxis>>; + +using InterpolatedBFieldMap2D = + Acts::InterpolatedBFieldMap<InterpolatedMapper2D>; +using InterpolatedBFieldMap3D = + Acts::InterpolatedBFieldMap<InterpolatedMapper3D>; + +namespace Jug { + +//namespace Options { +// +//// common bfield options, with a bf prefix +//void addBFieldOptions(boost::program_options::options_description& opt) { +// opt.add_options()("bf-map", po::value<std::string>()->default_value(""), +// "Set this string to point to the bfield source file." +// "That can either be a '.txt', a '.csv' or a '.root' file. " +// "Omit for a constant magnetic field.")( +// "bf-name", po::value<std::string>()->default_value("bField"), +// "In case your field map file is given in root format, please specify " +// "the " +// "name of the TTree.")( +// "bf-gridpoints", po::value<size_t>()->default_value(100000), +// "Estimate of number of grid points, " +// "needed for allocation, only for txt and csv files.")( +// "bf-lscalor", po::value<double>()->default_value(1.), +// "The default unit for the grid " +// "points is mm. In case the grid points of your field map has another " +// "unit, please set the scalor to mm.")( +// "bf-bscalor", po::value<double>()->default_value(1.), +// "The default unit for the magnetic field values is Tesla. In case the " +// "grid points of your field map has another unit, please set the " +// "scalor " +// "to [T].")( +// "bf-rz", po::value<bool>()->default_value(false), +// "Please set this flag to true, if your grid points and your " +// "magnetic field values are given in 'rz'. The default is 'xyz'.")( +// "bf-foctant", po::value<bool>()->default_value(false), +// "Please set this flag to true, if your field map is only given for the " +// "first octant/quadrant and should be symmetrically created for all " +// "other " +// "octants/quadrants.")( +// "bf-values", po::value<Reals<3>>()->default_value({{0., 0., 0.}}), +// "In case no magnetic field map is handed over. A constant magnetic " +// "field will be created automatically. The values can be set with this " +// "options. Please hand over the coordinates in cartesian coordinates: " +// "{Bx,By,Bz} in Tesla.")( +// "bf-context-scalable", po::value<bool>()->default_value(false), +// "This is for testing the event dependent magnetic field scaling."); +//} + +// create the bfield maps +//BFieldVariant readBField(const boost::program_options::variables_map& vm) { +// std::string bfieldmap = "constfield"; +// +// enum BFieldMapType { constant = 0, root = 1, text = 2 }; +// +// std::shared_ptr<InterpolatedBFieldMap2D> map2D = nullptr; +// std::shared_ptr<InterpolatedBFieldMap3D> map3D = nullptr; +// std::shared_ptr<Acts::ConstantBField> mapConst = nullptr; +// std::shared_ptr<Jug::BField::ScalableBField> mapScale = nullptr; +// +// int bfieldmaptype = constant; +// if (vm.count("bf-map") && vm["bf-map"].template as<std::string>() != "") { +// bfieldmap = vm["bf-map"].template as<std::string>(); +// std::cout << "- read in magnetic field map: " +// << vm["bf-map"].template as<std::string>() << std::endl; +// if (bfieldmap.find(".root") != std::string::npos) { +// std::cout << "- root format for magnetic field detected" << std::endl; +// bfieldmaptype = root; +// } else if (bfieldmap.find(".txt") != std::string::npos || +// bfieldmap.find(".csv") != std::string::npos) { +// std::cout << "- txt format for magnetic field detected" << std::endl; +// bfieldmaptype = text; +// } else { +// std::cout << "- magnetic field format could not be detected"; +// std::cout << " use '.root', '.txt', or '.csv'." << std::endl; +// throw std::runtime_error("Invalid BField options"); +// } +// } +// if (bfieldmaptype == text && vm.count("bf-gridpoints")) { +// std::cout << "- number of points set to: " +// << vm["bf-gridpoints"].template as<size_t>() << std::endl; +// } +// double lscalor = 1.; +// if (bfieldmaptype != constant && vm.count("bf-lscalor")) { +// lscalor = vm["bf-lscalor"].template as<double>(); +// std::cout << "- length scalor to mm set to: " << lscalor << std::endl; +// } +// double bscalor = 1.; +// if (vm.count("bf-bscalor")) { +// bscalor = vm["bf-bscalor"].template as<double>(); +// std::cout << "- BField (scalor to/in) Tesla set to: " << bscalor +// << std::endl; +// } +// if (bfieldmaptype != constant && vm["bf-rz"].template as<bool>()) +// std::cout << "- BField map is given in 'rz' coordiantes." << std::endl; +// else if (bfieldmaptype != constant) +// std::cout << "- BField map is given in 'xyz' coordiantes." << std::endl; +// +// if (bfieldmaptype != constant && vm["bf-foctant"].template as<bool>()) { +// std::cout +// << "- Only the first octant/quadrant is given, bField map will be " +// "symmetrically created for all other octants/quadrants" +// << std::endl; +// } +// +// // Declare the mapper +// double lengthUnit = lscalor * Acts::UnitConstants::mm; +// double BFieldUnit = bscalor * Acts::UnitConstants::T; +// +// // set the mapper - foort +// if (bfieldmaptype == root) { +// if (vm["bf-rz"].template as<bool>()) { +// auto mapper2D = Jug::BField::root::fieldMapperRZ( +// [](std::array<size_t, 2> binsRZ, std::array<size_t, 2> nBinsRZ) { +// return (binsRZ.at(1) * nBinsRZ.at(0) + binsRZ.at(0)); +// }, +// vm["bf-map"].template as<std::string>(), +// vm["bf-name"].template as<std::string>(), lengthUnit, BFieldUnit, +// vm["bf-foctant"].template as<bool>()); +// +// // create field mapping +// InterpolatedBFieldMap2D::Config config2D(std::move(mapper2D)); +// config2D.scale = bscalor; +// // create BField service +// return std::make_shared<InterpolatedBFieldMap2D>(std::move(config2D)); +// +// } else { +// auto mapper3D = Jug::BField::root::fieldMapperXYZ( +// [](std::array<size_t, 3> binsXYZ, std::array<size_t, 3> nBinsXYZ) { +// return (binsXYZ.at(0) * (nBinsXYZ.at(1) * nBinsXYZ.at(2)) + +// binsXYZ.at(1) * nBinsXYZ.at(2) + binsXYZ.at(2)); +// }, +// vm["bf-map"].template as<std::string>(), +// vm["bf-name"].template as<std::string>(), lengthUnit, BFieldUnit, +// vm["bf-foctant"].template as<bool>()); +// +// // create field mapping +// InterpolatedBFieldMap3D::Config config3D(std::move(mapper3D)); +// config3D.scale = bscalor; +// // create BField service +// return std::make_shared<InterpolatedBFieldMap3D>(std::move(config3D)); +// } +// } else if (bfieldmaptype == text) { +// if (vm["bf-rz"].template as<bool>()) { +// auto mapper2D = Jug::BField::txt::fieldMapperRZ( +// [](std::array<size_t, 2> binsRZ, std::array<size_t, 2> nBinsRZ) { +// return (binsRZ.at(1) * nBinsRZ.at(0) + binsRZ.at(0)); +// }, +// vm["bf-map"].template as<std::string>(), lengthUnit, BFieldUnit, +// vm["bf-gridpoints"].template as<size_t>(), +// vm["bf-foctant"].template as<bool>()); +// +// // create field mapping +// InterpolatedBFieldMap2D::Config config2D(std::move(mapper2D)); +// config2D.scale = bscalor; +// // create BField service +// return std::make_shared<InterpolatedBFieldMap2D>(std::move(config2D)); +// +// } else { +// auto mapper3D = Jug::BField::txt::fieldMapperXYZ( +// [](std::array<size_t, 3> binsXYZ, std::array<size_t, 3> nBinsXYZ) { +// return (binsXYZ.at(0) * (nBinsXYZ.at(1) * nBinsXYZ.at(2)) + +// binsXYZ.at(1) * nBinsXYZ.at(2) + binsXYZ.at(2)); +// }, +// vm["bf-map"].template as<std::string>(), lengthUnit, BFieldUnit, +// vm["bf-gridpoints"].template as<size_t>(), +// vm["bf-foctant"].template as<bool>()); +// +// // create field mapping +// InterpolatedBFieldMap3D::Config config3D(std::move(mapper3D)); +// config3D.scale = bscalor; +// // create BField service +// return std::make_shared<InterpolatedBFieldMap3D>(std::move(config3D)); +// } +// } else { // constant +// // No bfield map is handed over +// // get the constant bField values +// auto bFieldValues = vm["bf-values"].template as<Reals<3>>(); +// if (vm["bf-context-scalable"].template as<bool>()) { +// // Create the scalable magnetic field +// return std::make_shared<Jug::BField::ScalableBField>( +// bFieldValues.at(0) * Acts::UnitConstants::T, +// bFieldValues.at(1) * Acts::UnitConstants::T, +// bFieldValues.at(2) * Acts::UnitConstants::T); +// } else { +// // Create the constant magnetic field +// return std::make_shared<Acts::ConstantBField>( +// bFieldValues.at(0) * Acts::UnitConstants::T, +// bFieldValues.at(1) * Acts::UnitConstants::T, +// bFieldValues.at(2) * Acts::UnitConstants::T); +// } +// } +//} +//} // namespace Options +} // namespace Jug diff --git a/JugBase/src/Plugins/BFieldScalor.cpp b/JugBase/src/Plugins/BFieldScalor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c4f0e28a26407cc6193c759b7a2a80c8bc693a0c --- /dev/null +++ b/JugBase/src/Plugins/BFieldScalor.cpp @@ -0,0 +1,27 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2019 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "JugBase/BField/BFieldScalor.hpp" + +#include "JugBase/BField/ScalableBField.hpp" + +#include <cmath> + +Jug::BField::BFieldScalor::BFieldScalor( + const Jug::BField::BFieldScalor::Config& cfg, + std::unique_ptr<const Acts::Logger> logger) + : m_cfg(cfg), m_logger(std::move(logger)) {} + +Jug::ProcessCode Jug::BField::BFieldScalor::decorate( + AlgorithmContext& context) { + ScalableBFieldContext bFieldContext{ + std::pow(m_cfg.scalor, context.eventNumber)}; + context.magFieldContext = std::make_any<ScalableBFieldContext>(bFieldContext); + + return ProcessCode::SUCCESS; +} diff --git a/JugBase/src/Plugins/BFieldUtils.cpp b/JugBase/src/Plugins/BFieldUtils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0e778609a9209b75fcaaa638172283334928cb44 --- /dev/null +++ b/JugBase/src/Plugins/BFieldUtils.cpp @@ -0,0 +1,201 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2017 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "JugBase/BField/BFieldUtils.hpp" + +#include "Acts/MagneticField/BFieldMapUtils.hpp" +#include "Acts/Utilities/detail/Axis.hpp" +#include "Acts/Utilities/detail/Grid.hpp" + +#include <fstream> + +#include "TFile.h" +#include "TROOT.h" +#include "TTree.h" + +Acts::InterpolatedBFieldMapper< + Acts::detail::Grid<Acts::Vector2, Acts::detail::EquidistantAxis, + Acts::detail::EquidistantAxis>> +Jug::BField::txt::fieldMapperRZ( + std::function<size_t(std::array<size_t, 2> binsRZ, + std::array<size_t, 2> nBinsRZ)> + localToGlobalBin, + std::string fieldMapFile, double lengthUnit, double BFieldUnit, + size_t nPoints, bool firstQuadrant) { + /// [1] Read in field map file + // Grid position points in r and z + std::vector<double> rPos; + std::vector<double> zPos; + // components of magnetic field on grid points + std::vector<Acts::Vector2> bField; + // reserve estimated size + rPos.reserve(nPoints); + zPos.reserve(nPoints); + bField.reserve(nPoints); + // [1] Read in file and fill values + std::ifstream map_file(fieldMapFile.c_str(), std::ios::in); + std::string line; + double r = 0., z = 0.; + double br = 0., bz = 0.; + while (std::getline(map_file, line)) { + if (line.empty() || line[0] == '%' || line[0] == '#' || + line.find_first_not_of(' ') == std::string::npos) + continue; + + std::istringstream tmp(line); + tmp >> r >> z >> br >> bz; + rPos.push_back(r); + zPos.push_back(z); + bField.push_back(Acts::Vector2(br, bz)); + } + map_file.close(); + /// [2] use helper function in core + return Acts::fieldMapperRZ(localToGlobalBin, rPos, zPos, bField, lengthUnit, + BFieldUnit, firstQuadrant); +} + +Acts::InterpolatedBFieldMapper<Acts::detail::Grid< + Acts::Vector3, Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis, + Acts::detail::EquidistantAxis>> +Jug::BField::txt::fieldMapperXYZ( + std::function<size_t(std::array<size_t, 3> binsXYZ, + std::array<size_t, 3> nBinsXYZ)> + localToGlobalBin, + std::string fieldMapFile, double lengthUnit, double BFieldUnit, + size_t nPoints, bool firstOctant) { + /// [1] Read in field map file + // Grid position points in x, y and z + std::vector<double> xPos; + std::vector<double> yPos; + std::vector<double> zPos; + // components of magnetic field on grid points + std::vector<Acts::Vector3> bField; + // reserve estimated size + xPos.reserve(nPoints); + yPos.reserve(nPoints); + zPos.reserve(nPoints); + bField.reserve(nPoints); + // [1] Read in file and fill values + std::ifstream map_file(fieldMapFile.c_str(), std::ios::in); + std::string line; + double x = 0., y = 0., z = 0.; + double bx = 0., by = 0., bz = 0.; + while (std::getline(map_file, line)) { + if (line.empty() || line[0] == '%' || line[0] == '#' || + line.find_first_not_of(' ') == std::string::npos) + continue; + + std::istringstream tmp(line); + tmp >> x >> y >> z >> bx >> by >> bz; + xPos.push_back(x); + yPos.push_back(y); + zPos.push_back(z); + bField.push_back(Acts::Vector3(bx, by, bz)); + } + map_file.close(); + + return Acts::fieldMapperXYZ(localToGlobalBin, xPos, yPos, zPos, bField, + lengthUnit, BFieldUnit, firstOctant); +} + +Acts::InterpolatedBFieldMapper< + Acts::detail::Grid<Acts::Vector2, Acts::detail::EquidistantAxis, + Acts::detail::EquidistantAxis>> +Jug::BField::root::fieldMapperRZ( + std::function<size_t(std::array<size_t, 2> binsRZ, + std::array<size_t, 2> nBinsRZ)> + localToGlobalBin, + std::string fieldMapFile, std::string treeName, double lengthUnit, + double BFieldUnit, bool firstQuadrant) { + /// [1] Read in field map file + // Grid position points in r and z + std::vector<double> rPos; + std::vector<double> zPos; + // components of magnetic field on grid points + std::vector<Acts::Vector2> bField; + // [1] Read in file and fill values + TFile* inputFile = TFile::Open(fieldMapFile.c_str()); + TTree* tree = (TTree*)inputFile->Get(treeName.c_str()); + Int_t entries = tree->GetEntries(); + + double r, z; + double Br, Bz; + + tree->SetBranchAddress("r", &r); + tree->SetBranchAddress("z", &z); + + tree->SetBranchAddress("Br", &Br); + tree->SetBranchAddress("Bz", &Bz); + + // reserve size + rPos.reserve(entries); + zPos.reserve(entries); + bField.reserve(entries); + + for (int i = 0; i < entries; i++) { + tree->GetEvent(i); + rPos.push_back(r); + zPos.push_back(z); + bField.push_back(Acts::Vector2(Br, Bz)); + } + inputFile->Close(); + /// [2] use helper function in core + return Acts::fieldMapperRZ(localToGlobalBin, rPos, zPos, bField, lengthUnit, + BFieldUnit, firstQuadrant); +} + +Acts::InterpolatedBFieldMapper<Acts::detail::Grid< + Acts::Vector3, Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis, + Acts::detail::EquidistantAxis>> +Jug::BField::root::fieldMapperXYZ( + std::function<size_t(std::array<size_t, 3> binsXYZ, + std::array<size_t, 3> nBinsXYZ)> + localToGlobalBin, + std::string fieldMapFile, std::string treeName, double lengthUnit, + double BFieldUnit, bool firstOctant) { + /// [1] Read in field map file + // Grid position points in x, y and z + std::vector<double> xPos; + std::vector<double> yPos; + std::vector<double> zPos; + // components of magnetic field on grid points + std::vector<Acts::Vector3> bField; + // [1] Read in file and fill values + TFile* inputFile = TFile::Open(fieldMapFile.c_str()); + TTree* tree = (TTree*)inputFile->Get(treeName.c_str()); + Int_t entries = tree->GetEntries(); + + double x, y, z; + double Bx, By, Bz; + + tree->SetBranchAddress("x", &x); + tree->SetBranchAddress("y", &y); + tree->SetBranchAddress("z", &z); + + tree->SetBranchAddress("Bx", &Bx); + tree->SetBranchAddress("By", &By); + tree->SetBranchAddress("Bz", &Bz); + + // reserve size + xPos.reserve(entries); + yPos.reserve(entries); + zPos.reserve(entries); + bField.reserve(entries); + + for (int i = 0; i < entries; i++) { + tree->GetEvent(i); + xPos.push_back(x); + yPos.push_back(y); + zPos.push_back(z); + bField.push_back(Acts::Vector3(Bx, By, Bz)); + } + inputFile->Close(); + + return Acts::fieldMapperXYZ(localToGlobalBin, xPos, yPos, zPos, bField, + lengthUnit, BFieldUnit, firstOctant); +} diff --git a/JugBase/src/Utilities/Helpers.cpp b/JugBase/src/Utilities/Helpers.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a26d42067ed6123e270362b1b2d7f2395a2993b2 --- /dev/null +++ b/JugBase/src/Utilities/Helpers.cpp @@ -0,0 +1,103 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2019 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "JugBase/Utilities/Helpers.hpp" + +namespace Jug { + +namespace PlotHelpers { +TH1F* bookHisto(const char* histName, const char* histTitle, + const Binning& varBinning) { + TH1F* hist = new TH1F(histName, histTitle, varBinning.nBins, varBinning.min, + varBinning.max); + hist->GetXaxis()->SetTitle(varBinning.title.c_str()); + hist->GetYaxis()->SetTitle("Entries"); + hist->Sumw2(); + return hist; +} + +TH2F* bookHisto(const char* histName, const char* histTitle, + const Binning& varXBinning, const Binning& varYBinning) { + TH2F* hist = new TH2F(histName, histTitle, varXBinning.nBins, varXBinning.min, + varXBinning.max, varYBinning.nBins, varYBinning.min, + varYBinning.max); + hist->GetXaxis()->SetTitle(varXBinning.title.c_str()); + hist->GetYaxis()->SetTitle(varYBinning.title.c_str()); + hist->Sumw2(); + return hist; +} + +void fillHisto(TH1F* hist, float value, float weight) { + assert(hist != nullptr); + hist->Fill(value, weight); +} + +void fillHisto(TH2F* hist, float xValue, float yValue, float weight) { + assert(hist != nullptr); + hist->Fill(xValue, yValue, weight); +} + +void anaHisto(TH1D* inputHist, int j, TH1F* meanHist, TH1F* widthHist) { + // evaluate mean and width via the Gauss fit + assert(inputHist != nullptr); + if (inputHist->GetEntries() > 0) { + TFitResultPtr r = inputHist->Fit("gaus", "QS0"); + if (r.Get() and ((r->Status() % 1000) == 0)) { + // fill the mean and width into 'j'th bin of the meanHist and widthHist, + // respectively + meanHist->SetBinContent(j, r->Parameter(1)); + meanHist->SetBinError(j, r->ParError(1)); + widthHist->SetBinContent(j, r->Parameter(2)); + widthHist->SetBinError(j, r->ParError(2)); + } + } +} + +TEfficiency* bookEff(const char* effName, const char* effTitle, + const Binning& varBinning) { + TEfficiency* efficiency = new TEfficiency(effName, effTitle, varBinning.nBins, + varBinning.min, varBinning.max); + return efficiency; +} + +TEfficiency* bookEff(const char* effName, const char* effTitle, + const Binning& varXBinning, const Binning& varYBinning) { + TEfficiency* efficiency = new TEfficiency( + effName, effTitle, varXBinning.nBins, varXBinning.min, varXBinning.max, + varYBinning.nBins, varYBinning.min, varYBinning.max); + return efficiency; +} + +void fillEff(TEfficiency* efficiency, float value, bool status) { + assert(efficiency != nullptr); + efficiency->Fill(status, value); +} + +void fillEff(TEfficiency* efficiency, float xValue, float yValue, bool status) { + assert(efficiency != nullptr); + efficiency->Fill(status, xValue, yValue); +} + +TProfile* bookProf(const char* profName, const char* profTitle, + const Binning& varXBinning, const Binning& varYBinning) { + TProfile* prof = + new TProfile(profName, profTitle, varXBinning.nBins, varXBinning.min, + varXBinning.max, varYBinning.min, varYBinning.max); + prof->GetXaxis()->SetTitle(varXBinning.title.c_str()); + prof->GetYaxis()->SetTitle(varYBinning.title.c_str()); + return prof; +} + +void fillProf(TProfile* profile, float xValue, float yValue, float weight) { + assert(profile != nullptr); + profile->Fill(xValue, yValue, weight); +} + +} // namespace PlotHelpers + +} // namespace Jug diff --git a/JugBase/src/Utilities/Options.cpp b/JugBase/src/Utilities/Options.cpp new file mode 100644 index 0000000000000000000000000000000000000000..024fc9d3bcebc0735a6978d95932a1d8a4da58f8 --- /dev/null +++ b/JugBase/src/Utilities/Options.cpp @@ -0,0 +1,162 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2020 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "JugBase/Utilities/Options.hpp" + +#include <algorithm> +#include <istream> +#include <ostream> +#include <stdexcept> + +namespace { +constexpr char s_separator = ':'; +} + +// interval + +std::istream& Jug::Options::operator>>( + std::istream& is, Jug::Options::Interval& interval) { + std::string buf; + is >> buf; + + // default to an unbounded interval + interval.lower.reset(); + interval.upper.reset(); + + // find the limit separator + auto pos = buf.find_first_of(s_separator); + // no separator -> invalid input -> unbounded interval + if (pos == std::string::npos) { + return is; + } + + // if it exists, parse limit before separator + if (0 < pos) { + auto lowerStr = buf.substr(0, pos); + interval.lower = std::stod(lowerStr); + } + // if it exists, parse limit after separator + if ((pos + 1) < buf.size()) { + auto upperStr = buf.substr(pos + 1); + interval.upper = std::stod(upperStr); + } + + return is; +} + +std::ostream& Jug::Options::operator<<( + std::ostream& os, const Jug::Options::Interval& interval) { + if (not interval.lower.has_value() and not interval.upper.has_value()) { + os << "unbounded"; + } else { + if (interval.lower.has_value()) { + os << interval.lower.value(); + } + os << s_separator; + if (interval.upper.has_value()) { + os << interval.upper.value(); + } + } + return os; +} + +// helper functions to parse and print multiple values + +namespace { + +template <typename value_t, typename converter_t> +void parseVariable(std::istream& is, std::vector<value_t>& values, + converter_t&& convert) { + values.clear(); + + std::string buf; + is >> buf; + std::string bufValue; + std::string::size_type pos = 0; + std::string::size_type end = std::string::npos; + do { + end = buf.find_first_of(s_separator, pos); + if (end == std::string::npos) { + // last element; take the rest of the buffer + bufValue = buf.substr(pos); + } else { + bufValue = buf.substr(pos, end - pos); + pos = end + 1u; + } + values.push_back(convert(bufValue)); + } while (end != std::string::npos); +} + +template <typename value_t, typename converter_t> +void parseFixed(std::istream& is, size_t size, value_t* values, + converter_t&& convert) { + // reserve space for the expected number of values + std::vector<value_t> tmp(size, 0); + parseVariable(is, tmp, std::forward<converter_t>(convert)); + if (tmp.size() < size) { + throw std::invalid_argument( + "Not enough values for fixed-size user option, expected " + + std::to_string(size) + " received " + std::to_string(tmp.size())); + } + if (size < tmp.size()) { + throw std::invalid_argument( + "Too many values for fixed-size user option, expected " + + std::to_string(size) + " received " + std::to_string(tmp.size())); + } + std::copy(tmp.begin(), tmp.end(), values); +} + +template <typename value_t> +void print(std::ostream& os, size_t size, const value_t* values) { + for (size_t i = 0; i < size; ++i) { + if (0u < i) { + os << s_separator; + } + os << values[i]; + } +} + +} // namespace + +// fixed and variable number of generic values + +void Jug::Options::detail::parseDoublesFixed(std::istream& is, + size_t size, + double* values) { + parseFixed(is, size, values, + [](const std::string& s) { return std::stod(s); }); +} + +void Jug::Options::detail::parseDoublesVariable( + std::istream& is, std::vector<double>& values) { + parseVariable(is, values, [](const std::string& s) { return std::stod(s); }); +} + +void Jug::Options::detail::printDoubles(std::ostream& os, size_t size, + const double* values) { + print(os, size, values); +} + +// fixed and variable number of integers + +void Jug::Options::detail::parseIntegersFixed(std::istream& is, + size_t size, + int* values) { + parseFixed(is, size, values, + [](const std::string& s) { return std::stoi(s); }); +} + +void Jug::Options::detail::parseIntegersVariable( + std::istream& is, std::vector<int>& values) { + parseVariable(is, values, [](const std::string& s) { return std::stoi(s); }); +} + +void Jug::Options::detail::printIntegers(std::ostream& os, size_t size, + const int* values) { + print(os, size, values); +} diff --git a/JugBase/src/Utilities/Paths.cpp b/JugBase/src/Utilities/Paths.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cc4d3bff1d71a5788ca5dc32c6750300bfa2dc14 --- /dev/null +++ b/JugBase/src/Utilities/Paths.cpp @@ -0,0 +1,112 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2017 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "JugBase/Utilities/Paths.hpp" + +#include "Acts/Utilities/Logger.hpp" + +#include <charconv> +#include <cstdio> +#include <regex> +#include <sstream> +#include <stdexcept> + +#include <boost/filesystem.hpp> + +std::string Jug::ensureWritableDirectory(const std::string& dir) { + using boost::filesystem::current_path; + using boost::filesystem::path; + + auto dir_path = dir.empty() ? current_path() : path(dir); + if (exists(dir_path) and not is_directory(dir_path)) { + throw std::runtime_error("'" + dir + + "' already exists but is not a directory"); + } + create_directories(dir_path); + return canonical(dir_path).native(); +} + +std::string Jug::joinPaths(const std::string& dir, + const std::string& name) { + if (dir.empty()) { + return name; + } else { + return dir + '/' + name; + } +} + +std::string Jug::perEventFilepath(const std::string& dir, + const std::string& name, + size_t event) { + char prefix[64]; + + snprintf(prefix, sizeof(prefix), "event%09zu-", event); + + if (dir.empty()) { + return prefix + name; + } else { + return dir + '/' + prefix + name; + } +} + +std::pair<size_t, size_t> Jug::determineEventFilesRange( + const std::string& dir, const std::string& name) { + using boost::filesystem::current_path; + using boost::filesystem::directory_iterator; + using boost::filesystem::path; + + ACTS_LOCAL_LOGGER( + Acts::getDefaultLogger("EventFilesRange", Acts::Logging::VERBOSE)); + + // ensure directory path is valid + auto dir_path = dir.empty() ? current_path() : path(dir); + if (not exists(dir_path)) { + throw std::runtime_error("'" + dir_path.native() + "' does not exists"); + } + if (not is_directory(dir_path)) { + throw std::runtime_error("'" + dir_path.native() + "' is not a directory"); + } + + // invalid default range that allows simple restriction later on + size_t eventMin = SIZE_MAX; + size_t eventMax = 0; + + // filter matching event files from the directory listing + std::string filename; + std::regex re("^event([0-9]+)-" + name + "$"); + std::cmatch match; + + for (const auto& f : directory_iterator(dir_path)) { + if ((not exists(f.status())) or (not is_regular_file(f.status()))) { + continue; + } + // keep a copy so the match can refer to the underlying const char* + filename = f.path().filename().native(); + if (std::regex_match(filename.c_str(), match, re)) { + ACTS_VERBOSE("Matching file " << filename); + + // first sub_match is the whole string, second should be the event number + size_t event = 0; + auto ret = std::from_chars(match[1].first, match[1].second, event); + if (ret.ptr == match[1].first) { + throw std::runtime_error( + "Could not extract event number from filename"); + } + // enlarge available event range + eventMin = std::min(eventMin, event); + eventMax = std::max(eventMax, event); + } + } + ACTS_VERBOSE("Detected event range [" << eventMin << "," << eventMax << "]"); + + // should only occur if no files matched and the initial values persisted. + if (eventMax < eventMin) { + return std::make_pair(0u, 0u); + } + return std::make_pair(eventMin, eventMax + 1); +} diff --git a/JugBase/src/components/GeoSvc.cpp b/JugBase/src/components/GeoSvc.cpp index d2f5f85efc8bd60ee612b65d929a284c47203624..e85708feb013974ee90d42244547611766ced6c1 100644 --- a/JugBase/src/components/GeoSvc.cpp +++ b/JugBase/src/components/GeoSvc.cpp @@ -17,6 +17,44 @@ #include "Acts/Geometry/TrackingGeometry.hpp" #include "Acts/Plugins/DD4hep/ConvertDD4hepDetector.hpp" +#include "Acts/Surfaces/PlaneSurface.hpp" + + +void draw_surfaces(std::shared_ptr<const Acts::TrackingGeometry> trk_geo, const std::string& fname) +{ + using namespace Acts; + Acts::GeometryContext tgContext = Acts::GeometryContext(); + std::vector<const Surface*> surfaces; + + trk_geo->visitSurfaces([&](const Acts::Surface* surface) { + // for now we just require a valid surface + if (not surface) { + return; + } + surfaces.push_back(surface); + }); + std::ofstream os; + os.open(fname); + os << std::fixed << std::setprecision(4); + size_t nVtx = 0; + for (const auto& srfx : surfaces) { + const PlaneSurface* srf = dynamic_cast<const PlaneSurface*>(srfx); + const PlanarBounds* bounds = dynamic_cast<const PlanarBounds*>(&srf->bounds()); + for (const auto& vtxloc : bounds->vertices()) { + Vector3 vtx = srf->transform(tgContext) * Vector3(vtxloc.x(), vtxloc.y(), 0); + os << "v " << vtx.x() << " " << vtx.y() << " " << vtx.z() << "\n"; + } + // connect them + os << "f"; + for (size_t i = 1; i <= bounds->vertices().size(); ++i) { + os << " " << nVtx + i; + } + os << "\n"; + nVtx += bounds->vertices().size(); + } + os.close(); +} + using namespace Gaudi; DECLARE_COMPONENT(GeoSvc) @@ -85,8 +123,9 @@ StatusCode GeoSvc::initialize() { default: geoMsgLevel = Acts::Logging::VERBOSE; } - m_trackingGeo = std::move(Acts::convertDD4hepDetector(m_dd4hepgeo->world(), geoMsgLevel, Acts::equidistant, + m_trackingGeo = std::move(Acts::convertDD4hepDetector(m_dd4hepgeo->world(), Acts::Logging::VERBOSE, Acts::equidistant, Acts::equidistant, Acts::equidistant)); + draw_surfaces(m_trackingGeo, "Derp.obj"); return StatusCode::SUCCESS; } diff --git a/JugBase/src/components/GeoSvc.h b/JugBase/src/components/GeoSvc.h index 87fa21ce408bd11199fcfc935a08f44c1c10047f..2efeeec3c284fb31087fab16d1b2f0c42aa808c7 100644 --- a/JugBase/src/components/GeoSvc.h +++ b/JugBase/src/components/GeoSvc.h @@ -11,7 +11,7 @@ // Interface #include "JugBase/IGeoSvc.h" -#include "Acts/Utilities/Units.hpp" +#include "Acts/Definitions/Units.hpp" #include "DD4hep/DD4hepUnits.h" //using namespace Acts::UnitLiterals; @@ -27,17 +27,28 @@ #include "DDRec/SurfaceManager.h" #include "DDRec/Surface.h" +// Create a test context +//#define CHECK_ROTATION_ANGLE(t, a, tolerance) \ +// { \ +// Vector3 v = (*t) * Vector3(1, 0, 0); \ +// CHECK_CLOSE_ABS(VectorHelpers::phi(v), (a), tolerance); \ +// } + +//using SrfVec = std::vector<std::shared_ptr<const Surface>>; +void draw_surfaces(std::shared_ptr<const Acts::TrackingGeometry> trk_geo, const std::string& fname); + + class GeoSvc : public extends<Service, IGeoSvc> { public: GeoSvc(const std::string& name, ISvcLocator* svc); virtual ~GeoSvc(); - + virtual StatusCode initialize() final; - + virtual StatusCode finalize() final; - + /** Build the dd4hep geometry. * This function generates the DD4hep geometry. */ @@ -64,8 +75,6 @@ public: virtual double centralMagneticField() const { return m_dd4hepgeo->field().magneticField({0,0,0}).z()*(Acts::UnitConstants::T/dd4hep::tesla); } - -; private: @@ -76,9 +85,7 @@ private: /// Pointer to the interface to the DD4hep geometry dd4hep::Detector* m_dd4hepgeo; - std::shared_ptr<const dd4hep::rec::CellIDPositionConverter> m_cellid_converter = nullptr;//(*(m_geoSvc->detector())); - /// XML-files with the detector description Gaudi::Property<std::vector<std::string>> m_xmlFileNames{this, "detectors", {}, "Detector descriptions XML-files"}; diff --git a/JugReco/CMakeLists.txt b/JugReco/CMakeLists.txt index 5df1eed1d4cb4824d893837b837a8ee69c41f30a..9935c87515dc4313721cf2db06c9cc4058530c86 100644 --- a/JugReco/CMakeLists.txt +++ b/JugReco/CMakeLists.txt @@ -31,8 +31,10 @@ gaudi_add_module(JugRecoPlugins src/components/TrackerHitReconstruction.cpp src/components/TrackerSourceLinker.cpp src/components/TrackerSourcesLinker.cpp - src/components/TrackingHitsSourceLinker.cpp + #src/components/TrackingHitsSourceLinker.cpp src/components/TrackFindingAlgorithm.cpp + #src/components/TrackFittingAlgorithm.cpp + #src/components/TrackFittingFunction.cpp src/components/TestACTSLogger.cpp src/components/TrackParamTruthInit.cpp src/components/TrackParamClusterInit.cpp diff --git a/JugReco/JugReco/BField.h b/JugReco/JugReco/BField.h index b013d99194f9ed72ca052f3e273048c3938e4330..0d3bb15a1957f0062ff0289a21486b2c24ea8c5e 100644 --- a/JugReco/JugReco/BField.h +++ b/JugReco/JugReco/BField.h @@ -1,7 +1,7 @@ #ifndef Jug_BFIELD_HH #define Jug_BFIELD_HH 1 -#include "Acts/Utilities//Definitions.hpp" +#include "Acts//Definitions/Units.hpp" #include "Acts/Utilities/detail/AxisFwd.hpp" #include "Acts/Utilities/detail/GridFwd.hpp" #include <memory> @@ -9,7 +9,7 @@ #include<variant> #include "Acts/MagneticField/MagneticFieldContext.hpp" -#include "Acts/Utilities/Definitions.hpp" +#include "Acts/Definitions/Common.hpp" // Forward declarations namespace Acts { @@ -22,141 +22,138 @@ namespace Acts { } // namespace Acts namespace Jug { - //namespace BField { + // namespace BField { // class ScalableBField; //} -namespace BField { - -/// The Context to be handed around -struct ScalableBFieldContext { - double scalor = 1.; -}; - -/// @ingroup MagneticField -/// -/// @brief returns a given constant field value at every point -/// -/// This class is based on the constant magnetic field class -/// but allows a event based context -class ScalableBField final { - public: - struct Cache { - double scalor = 1.; - - /// @brief constructor with context - Cache(const Acts::MagneticFieldContext& mcfg) { - scalor = std::any_cast<const ScalableBFieldContext>(mcfg).scalor; - } - }; - - /// @brief construct constant magnetic field from field vector - /// - /// @param [in] B magnetic field vector in global coordinate system - explicit ScalableBField(Acts::Vector3D B) : m_BField(std::move(B)) {} - - /// @brief construct constant magnetic field from components - /// - /// @param [in] Bx magnetic field component in global x-direction - /// @param [in] By magnetic field component in global y-direction - /// @param [in] Bz magnetic field component in global z-direction - ScalableBField(double Bx = 0., double By = 0., double Bz = 0.) - : m_BField(Bx, By, Bz) {} - - /// @brief retrieve magnetic field value - /// - /// @param [in] position global position - /// @return magnetic field vector - /// - /// @note The @p position is ignored and only kept as argument to provide - /// a consistent interface with other magnetic field services. - Acts::Vector3D getField(const Acts::Vector3D& /*position*/) const { - return m_BField; - } - - /// @brief retrieve magnetic field value - /// - /// @param [in] position global position - /// @param [in] cache Cache object (is ignored) - /// @return magnetic field vector - /// - /// @note The @p position is ignored and only kept as argument to provide - /// a consistent interface with other magnetic field services. - Acts::Vector3D getField(const Acts::Vector3D& /*position*/, - Cache& cache) const { - return m_BField * cache.scalor; - } - - /// @brief retrieve magnetic field value & its gradient - /// - /// @param [in] position global position - /// @param [out] derivative gradient of magnetic field vector as (3x3) - /// matrix - /// @return magnetic field vector - /// - /// @note The @p position is ignored and only kept as argument to provide - /// a consistent interface with other magnetic field services. - /// @note currently the derivative is not calculated - /// @todo return derivative - Acts::Vector3D getFieldGradient( - const Acts::Vector3D& /*position*/, - Acts::ActsMatrixD<3, 3>& /*derivative*/) const { - return m_BField; - } - - /// @brief retrieve magnetic field value & its gradient - /// - /// @param [in] position global position - /// @param [out] derivative gradient of magnetic field vector as (3x3) - /// matrix - /// @param [in] cache Cache object (is ignored) - /// @return magnetic field vector - /// - /// @note The @p position is ignored and only kept as argument to provide - /// a consistent interface with other magnetic field services. - /// @note currently the derivative is not calculated - /// @todo return derivative - Acts::Vector3D getFieldGradient(const Acts::Vector3D& /*position*/, - Acts::ActsMatrixD<3, 3>& /*derivative*/, - Cache& cache) const { - return m_BField * cache.scalor; - } - - /// @brief check whether given 3D position is inside look-up domain - /// - /// @param [in] position global 3D position - /// @return @c true if position is inside the defined look-up grid, - /// otherwise @c false - /// @note The method will always return true for the constant B-Field - bool isInside(const Acts::Vector3D& /*position*/) const { return true; } - - /// @brief update magnetic field vector from components - /// - /// @param [in] Bx magnetic field component in global x-direction - /// @param [in] By magnetic field component in global y-direction - /// @param [in] Bz magnetic field component in global z-direction - void setField(double Bx, double By, double Bz) { m_BField << Bx, By, Bz; } - - /// @brief update magnetic field vector - /// - /// @param [in] B magnetic field vector in global coordinate system - void setField(const Acts::Vector3D& B) { m_BField = B; } - - private: - /// magnetic field vector - Acts::Vector3D m_BField; -}; + namespace BField { + + /// The Context to be handed around + struct ScalableBFieldContext { + double scalor = 1.; + }; + + /// @ingroup MagneticField + /// + /// @brief returns a given constant field value at every point + /// + /// This class is based on the constant magnetic field class + /// but allows a event based context + class ScalableBField final { + public: + struct Cache { + double scalor = 1.; + + /// @brief constructor with context + Cache(const Acts::MagneticFieldContext& mcfg) + { + scalor = std::any_cast<const ScalableBFieldContext>(mcfg).scalor; + } + }; + + /// @brief construct constant magnetic field from field vector + /// + /// @param [in] B magnetic field vector in global coordinate system + explicit ScalableBField(Acts::Vector3 B) : m_BField(std::move(B)) {} + + /// @brief construct constant magnetic field from components + /// + /// @param [in] Bx magnetic field component in global x-direction + /// @param [in] By magnetic field component in global y-direction + /// @param [in] Bz magnetic field component in global z-direction + ScalableBField(double Bx = 0., double By = 0., double Bz = 0.) : m_BField(Bx, By, Bz) {} + + /// @brief retrieve magnetic field value + /// + /// @param [in] position global position + /// @return magnetic field vector + /// + /// @note The @p position is ignored and only kept as argument to provide + /// a consistent interface with other magnetic field services. + Acts::Vector3 getField(const Acts::Vector3& /*position*/) const { return m_BField; } + + /// @brief retrieve magnetic field value + /// + /// @param [in] position global position + /// @param [in] cache Cache object (is ignored) + /// @return magnetic field vector + /// + /// @note The @p position is ignored and only kept as argument to provide + /// a consistent interface with other magnetic field services. + Acts::Vector3 getField(const Acts::Vector3& /*position*/, Cache& cache) const + { + return m_BField * cache.scalor; + } + + /// @brief retrieve magnetic field value & its gradient + /// + /// @param [in] position global position + /// @param [out] derivative gradient of magnetic field vector as (3x3) + /// matrix + /// @return magnetic field vector + /// + /// @note The @p position is ignored and only kept as argument to provide + /// a consistent interface with other magnetic field services. + /// @note currently the derivative is not calculated + /// @todo return derivative + Acts::Vector3 getFieldGradient(const Acts::Vector3& /*position*/, Acts::ActsMatrix<3, 3>& /*derivative*/) const + { + return m_BField; + } + + /// @brief retrieve magnetic field value & its gradient + /// + /// @param [in] position global position + /// @param [out] derivative gradient of magnetic field vector as (3x3) + /// matrix + /// @param [in] cache Cache object (is ignored) + /// @return magnetic field vector + /// + /// @note The @p position is ignored and only kept as argument to provide + /// a consistent interface with other magnetic field services. + /// @note currently the derivative is not calculated + /// @todo return derivative + Acts::Vector3 getFieldGradient(const Acts::Vector3& /*position*/, Acts::ActsMatrix<3, 3>& /*derivative*/, + Cache& cache) const + { + return m_BField * cache.scalor; + } + + /// @brief check whether given 3D position is inside look-up domain + /// + /// @param [in] position global 3D position + /// @return @c true if position is inside the defined look-up grid, + /// otherwise @c false + /// @note The method will always return true for the constant B-Field + bool isInside(const Acts::Vector3& /*position*/) const { return true; } + + /// @brief update magnetic field vector from components + /// + /// @param [in] Bx magnetic field component in global x-direction + /// @param [in] By magnetic field component in global y-direction + /// @param [in] Bz magnetic field component in global z-direction + void setField(double Bx, double By, double Bz) { m_BField << Bx, By, Bz; } + + /// @brief update magnetic field vector + /// + /// @param [in] B magnetic field vector in global coordinate system + void setField(const Acts::Vector3& B) { m_BField = B; } + + private: + /// magnetic field vector + Acts::Vector3 m_BField; + }; } // namespace BField } // namespace Jug using InterpolatedMapper2D = Acts::InterpolatedBFieldMapper< - Acts::detail::Grid<Acts::Vector2D, Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis>>; + Acts::detail::Grid<Acts::Vector2, Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis>>; using InterpolatedMapper3D = - Acts::InterpolatedBFieldMapper<Acts::detail::Grid<Acts::Vector3D, Acts::detail::EquidistantAxis, + Acts::InterpolatedBFieldMapper<Acts::detail::Grid<Acts::Vector3, Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis>>; -using InterpolatedBFieldMap2D = Acts::InterpolatedBFieldMap<InterpolatedMapper2D>; -using InterpolatedBFieldMap3D = Acts::InterpolatedBFieldMap<InterpolatedMapper3D>; +using InterpolatedBFieldMap2D = Acts::InterpolatedBFieldMap<InterpolatedMapper2D>; +using InterpolatedBFieldMap3D = Acts::InterpolatedBFieldMap<InterpolatedMapper3D>; using BFieldVariant = std::variant<std::shared_ptr<InterpolatedBFieldMap2D>, std::shared_ptr<InterpolatedBFieldMap3D>, std::shared_ptr<Acts::ConstantBField>, std::shared_ptr<Jug::BField::ScalableBField>>; diff --git a/JugReco/JugReco/Index.hpp b/JugReco/JugReco/Index.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cb4eed81c098f7b79b12e9b6fb6f4a358e874204 --- /dev/null +++ b/JugReco/JugReco/Index.hpp @@ -0,0 +1,55 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2019-2020 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include <cstdint> + +#include <boost/container/flat_map.hpp> + +namespace Jug { + +/// Index type to reference elements in a container. +/// +/// We do not expect to have more than 2^32 elements in any given container so a +/// fixed sized integer type is sufficient. +using Index = uint32_t; + +/// Store elements that are identified by an index, e.g. in another container. +/// +/// Each index can have zero or more associated elements. A typical case could +/// be to store all generating particles for a hit where the hit is identified +/// by its index in the hit container. +template <typename value_t> +using IndexMultimap = boost::container::flat_multimap<Index, value_t>; + +/// Invert the multimap, i.e. from a -> {b...} to b -> {a...}. +/// +/// @note This assumes that the value in the initial multimap is itself a +/// sortable index-like object, as would be the case when mapping e.g. +/// hit ids to particle ids/ barcodes. +template <typename value_t> +inline boost::container::flat_multimap<value_t, Index> invertIndexMultimap( + const IndexMultimap<value_t>& multimap) { + using InverseMultimap = boost::container::flat_multimap<value_t, Index>; + + // switch key-value without enforcing the new ordering (linear copy) + typename InverseMultimap::sequence_type unordered; + unordered.reserve(multimap.size()); + for (auto&& [index, value] : multimap) { + // value is now the key and the index is now the value + unordered.emplace_back(value, index); + } + + // adopting the unordered sequence will reestablish the correct order + InverseMultimap inverse; + inverse.adopt_sequence(std::move(unordered)); + return inverse; +} + +} // namespace ActsExamples diff --git a/JugReco/JugReco/IndexSourceLink.hpp b/JugReco/JugReco/IndexSourceLink.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cfdb48b91ba5eb62c2da545c57938d1edc59b6f2 --- /dev/null +++ b/JugReco/JugReco/IndexSourceLink.hpp @@ -0,0 +1,62 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2020 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include "JugReco/GeometryContainers.hpp" +#include "JugReco/Index.hpp" + +#include <cassert> + +namespace Jug { + + /// A source link that stores just an index. + /// + /// This is intentionally kept as barebones as possible. The source link + /// is just a reference and will be copied, moved around, etc. often. + /// Keeping it small and separate from the actual, potentially large, + /// measurement data should result in better overall performance. + /// Using an index instead of e.g. a pointer, means source link and + /// measurement are decoupled and the measurement represenation can be + /// easily changed without having to also change the source link. + class IndexSourceLink final { + public: + /// Construct from geometry identifier and index. + constexpr IndexSourceLink(Acts::GeometryIdentifier gid, Index idx) : m_geometryId(gid), m_index(idx) {} + + // Construct an invalid source link. Must be default constructible to + /// satisfy SourceLinkConcept. + IndexSourceLink() = default; + IndexSourceLink(const IndexSourceLink&) = default; + IndexSourceLink(IndexSourceLink&&) = default; + IndexSourceLink& operator=(const IndexSourceLink&) = default; + IndexSourceLink& operator=(IndexSourceLink&&) = default; + + /// Access the geometry identifier. + constexpr Acts::GeometryIdentifier geometryId() const { return m_geometryId; } + /// Access the index. + constexpr Index index() const { return m_index; } + + public: + Acts::GeometryIdentifier m_geometryId; + Index m_index; + + friend constexpr bool operator==(const IndexSourceLink& lhs, const IndexSourceLink& rhs) + { + return (lhs.m_geometryId == rhs.m_geometryId) and (lhs.m_index == rhs.m_index); + } + friend constexpr bool operator!=(const IndexSourceLink& lhs, const IndexSourceLink& rhs) { return not(lhs == rhs); } + }; + + /// Container of index source links. + /// + /// Since the source links provide a `.geometryId()` accessor, they can be + /// stored in an ordered geometry container. + using IndexSourceLinkContainer = GeometryIdMultiset<IndexSourceLink>; + +} // namespace Jug diff --git a/JugReco/JugReco/Measurement.hpp b/JugReco/JugReco/Measurement.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ccd7725cbac029f5a1105751e3da6fefb1dbfce3 --- /dev/null +++ b/JugReco/JugReco/Measurement.hpp @@ -0,0 +1,52 @@ +// Copyright (C) 2020 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include "Acts/EventData/Measurement.hpp" +#include "JugReco/IndexSourceLink.hpp" + +#include <cassert> +#include <vector> + +namespace Jug { + + /// Variable measurement type that can contain all possible combinations. + using Measurement = ::Acts::BoundVariantMeasurement<IndexSourceLink>; + /// Container of measurements. + /// + /// In contrast to the source links, the measurements themself must not be + /// orderable. The source links stored in the measurements are treated + /// as opaque here and no ordering is enforced on the stored measurements. + using MeasurementContainer = std::vector<Measurement>; + + /// Calibrator to convert an index source link to a measurement. + class MeasurementCalibrator { + public: + /// Construct an invalid calibrator. Required to allow copying. + MeasurementCalibrator() = default; + /// Construct using a user-provided container to chose measurements from. + MeasurementCalibrator(const MeasurementContainer& measurements) : m_measurements(&measurements) {} + + /// Find the measurement corresponding to the source link. + /// + /// @tparam parameters_t Track parameters type + /// @param sourceLink Input source link + /// @param parameters Input track parameters (unused) + template <typename parameters_t> + const Measurement& operator()(const IndexSourceLink& sourceLink, const parameters_t& /* parameters */) const + { + assert(m_measurements and "Undefined measurement container in DigitizedCalibrator"); + assert((sourceLink.index() < m_measurements->size()) and "Source link index is outside the container bounds"); + return (*m_measurements)[sourceLink.m_index]; + } + + private: + // use pointer so the calibrator is copyable and default constructible. + const MeasurementContainer* m_measurements = nullptr; + }; + +} // namespace Jug diff --git a/JugReco/JugReco/SimMultiTrajectory.hpp b/JugReco/JugReco/SimMultiTrajectory.hpp index 969a9e8f348767b080e9a88fb7e1583b58f65ec6..91b72ddcd4bc6cd425a1d2771fee33478cd2aae0 100644 --- a/JugReco/JugReco/SimMultiTrajectory.hpp +++ b/JugReco/JugReco/SimMultiTrajectory.hpp @@ -8,11 +8,11 @@ #pragma once -#include "JugReco/SourceLinks.h" //#include "ACTFW/Validation/ProtoTrackClassification.hpp" #include "Acts/EventData/MultiTrajectory.hpp" #include "Acts/EventData/TrackParameters.hpp" +#include "JugReco/IndexSourceLink.hpp" #include <unordered_map> #include <utility> @@ -48,7 +48,7 @@ struct SimMultiTrajectory { /// @param tTips The entry indices for trajectories in multiTrajectory /// @param parameters The fitted track parameters indexed by trajectory entry /// index - SimMultiTrajectory(const Acts::MultiTrajectory<SourceLink>& multiTraj, + SimMultiTrajectory(const Acts::MultiTrajectory<IndexSourceLink>& multiTraj, const std::vector<size_t>& tTips, const IndexedParams& parameters) : m_multiTrajectory(multiTraj), @@ -118,7 +118,7 @@ struct SimMultiTrajectory { /// @return The multiTrajectory with trajectory entry indices /// /// @note It could return an empty multiTrajectory - std::pair<std::vector<size_t>, Acts::MultiTrajectory<SourceLink>> + std::pair<std::vector<size_t>, Acts::MultiTrajectory<IndexSourceLink>> trajectory() const { return std::make_pair(m_trackTips, m_multiTrajectory); } @@ -149,7 +149,7 @@ struct SimMultiTrajectory { private: // The multiTrajectory - Acts::MultiTrajectory<SourceLink> m_multiTrajectory; + Acts::MultiTrajectory<IndexSourceLink> m_multiTrajectory; // The entry indices of trajectories stored in multiTrajectory std::vector<size_t> m_trackTips = {}; diff --git a/JugReco/JugReco/SourceLinks.h b/JugReco/JugReco/SourceLinks.h index d53ab710a89a325dda099c43c48c47317c9be082..86442375c79f8b5ecc965ba3703720613957bcae 100644 --- a/JugReco/JugReco/SourceLinks.h +++ b/JugReco/JugReco/SourceLinks.h @@ -27,8 +27,9 @@ class SourceLink { private: Acts::BoundVector m_values; Acts::BoundMatrix m_cov; - size_t m_dim = 0u; + size_t m_dim = 2; // store geo id copy to avoid indirection via truth hit + int32_t m_index; Acts::GeometryIdentifier m_geometryId; // need to store pointers to make the object copyable const Acts::Surface* m_surface; @@ -37,10 +38,11 @@ class SourceLink { public: SourceLink(const Acts::Surface& surface, //const ActsFatras::Hit& truthHit, - size_t dim, Acts::BoundVector values, Acts::BoundMatrix cov) + size_t dim, int32_t index, Acts::BoundVector values, Acts::BoundMatrix cov) : m_values(values), m_cov(cov), m_dim(dim), + m_index(index), m_geometryId(0),//truthHit.geometryId()), m_surface(&surface){} //m_truthHit(&truthHit) {} @@ -76,9 +78,14 @@ class SourceLink { friend constexpr bool operator==(const SourceLink& lhs, const SourceLink& rhs) { - return lhs.geometryId() == rhs.geometryId(); + + return (lhs.geometryId() == rhs.geometryId()) && (lhs.m_index == rhs.m_index); //lhs.m_truthHit == rhs.m_truthHit; } + friend constexpr bool operator!=(const SourceLink& lhs, + const SourceLink& rhs) { + return not(lhs == rhs); + } }; /// Store source links ordered by geometry identifier. diff --git a/JugReco/JugReco/Track.hpp b/JugReco/JugReco/Track.hpp index 595597599a1cc43b7b57123541ae3ba3ff0be521..57c3452cbea34ca76870dff618857a50cfc858b3 100644 --- a/JugReco/JugReco/Track.hpp +++ b/JugReco/JugReco/Track.hpp @@ -15,21 +15,19 @@ //#include "ACTFW/EventData/SimSourceLink.hpp" #include "Acts/EventData/MultiTrajectory.hpp" #include "Acts/EventData/TrackParameters.hpp" -#include "JugReco/SourceLinks.h" +#include "JugReco/IndexSourceLink.hpp" #include <vector> namespace Jug { - /// (Reconstructed) track parameters e.g. close to the vertex. - using TrackParameters = Acts::CurvilinearTrackParameters; - + using TrackParameters = ::Acts::BoundTrackParameters; /// Container of reconstructed track states for multiple tracks. using TrackParametersContainer = std::vector<TrackParameters>; /// MultiTrajectory definition - using Trajectory = Acts::MultiTrajectory<SourceLink>; + using Trajectory = Acts::MultiTrajectory<IndexSourceLink>; /// Container for the truth fitting/finding track(s) using TrajectoryContainer = std::vector<SimMultiTrajectory>; diff --git a/JugReco/src/components/ParticlesFromTrackFit.cpp b/JugReco/src/components/ParticlesFromTrackFit.cpp index 56b424be3ce4c26df72c0f8df8bd25066793b234..7b43f691de5388a07ee4cf46cb6ea11d2874356b 100644 --- a/JugReco/src/components/ParticlesFromTrackFit.cpp +++ b/JugReco/src/components/ParticlesFromTrackFit.cpp @@ -22,7 +22,7 @@ #include "eicd/ParticleCollection.h" #include "eicd/TrackerHitCollection.h" #include "eicd/TrackParametersCollection.h" -#include "JugReco/SourceLinks.h" +#include "JugReco/IndexSourceLink.hpp" #include "JugReco/Track.hpp" #include "Acts/Utilities/Helpers.hpp" diff --git a/JugReco/src/components/TrackFindingAlgorithm.cpp b/JugReco/src/components/TrackFindingAlgorithm.cpp index 52a6bacb3ef12b2c6efc4b2fd6151205c47cbaa6..c25e87666be7eb23693cfa21a1b373de581299a5 100644 --- a/JugReco/src/components/TrackFindingAlgorithm.cpp +++ b/JugReco/src/components/TrackFindingAlgorithm.cpp @@ -26,18 +26,20 @@ #include "Acts/Propagator/EigenStepper.hpp" #include "Acts/Propagator/Navigator.hpp" #include "Acts/Propagator/Propagator.hpp" -#include "Acts/Utilities/Definitions.hpp" +#include "Acts/Definitions/Common.hpp" #include "Acts/Utilities/Helpers.hpp" #include "Acts/Utilities/Logger.hpp" -#include "Acts/Utilities/Units.hpp" +#include "Acts/Definitions/Units.hpp" #include "JugBase/DataHandle.h" #include "JugBase/IGeoSvc.h" #include "JugReco/GeometryContainers.hpp" -#include "JugReco/SourceLinks.h" +//#include "JugReco/SourceLinks.h" +#include "JugReco/Measurement.hpp" +#include "JugReco/Index.hpp" +#include "JugReco/IndexSourceLink.hpp" #include "JugReco/Track.hpp" #include "JugReco/BField.h" -#include "JugReco/SourceLinks.h" #include "eicd/TrackerHitCollection.h" @@ -47,19 +49,21 @@ #include <random> #include <stdexcept> - - namespace Jug::Reco { using namespace Acts::UnitLiterals; - TrackFindingAlgorithm::TrackFindingAlgorithm(const std::string& name, ISvcLocator* svcLoc) : GaudiAlgorithm(name, svcLoc) { + TrackFindingAlgorithm::TrackFindingAlgorithm(const std::string& name, ISvcLocator* svcLoc) + : GaudiAlgorithm(name, svcLoc) + { declareProperty("inputSourceLinks", m_inputSourceLinks, ""); + declareProperty("inputMeasurements", m_inputMeasurements, ""); declareProperty("inputInitialTrackParameters", m_inputInitialTrackParameters, ""); declareProperty("outputTrajectories", m_outputTrajectories, ""); } - StatusCode TrackFindingAlgorithm::initialize() { + StatusCode TrackFindingAlgorithm::initialize() + { if (GaudiAlgorithm::initialize().isFailure()) return StatusCode::FAILURE; m_geoSvc = service("GeoSvc"); @@ -68,24 +72,22 @@ namespace Jug::Reco { << "Make sure you have GeoSvc and SimSvc in the right order in the configuration." << endmsg; return StatusCode::FAILURE; } - m_BField = std::make_shared<Acts::ConstantBField>(Acts::Vector3D{0.0, 0.0, m_geoSvc->centralMagneticField()}); - m_fieldctx = BFieldVariant(m_BField); - + m_BField = std::make_shared<Acts::ConstantBField>(Acts::Vector3{0.0, 0.0, m_geoSvc->centralMagneticField()}); + m_fieldctx = BFieldVariant(m_BField); // chi2 and #sourclinks per surface cutoffs - m_sourcelinkSelectorCfg = { {Acts::GeometryIdentifier(), {15, 10}}, + m_sourcelinkSelectorCfg = { + {Acts::GeometryIdentifier(), {15, 10}}, }; - - findTracks = TrackFindingAlgorithm::makeTrackFinderFunction(m_geoSvc->trackingGeometry(), m_BField); - + m_trackFinderFunc = TrackFindingAlgorithm::makeTrackFinderFunction(m_geoSvc->trackingGeometry(), m_BField); return StatusCode::SUCCESS; } - StatusCode TrackFindingAlgorithm::execute() { + StatusCode TrackFindingAlgorithm::execute() + { // Read input data - const SourceLinkContainer* src_links = m_inputSourceLinks.get(); + const IndexSourceLinkContainer* src_links = m_inputSourceLinks.get(); const TrackParametersContainer* init_trk_params = m_inputInitialTrackParameters.get(); - // const auto sourceLinks = ctx.eventStore.get<SourceLinkContainer>(m_cfg.inputSourceLinks); - // const auto initialParameters = ctx.eventStore.get<TrackParametersContainer>(m_cfg.inputInitialTrackParameters); + const MeasurementContainer* measurements = m_inputMeasurements.get(); //// Prepare the output data with MultiTrajectory // TrajectoryContainer trajectories; @@ -93,7 +95,7 @@ namespace Jug::Reco { trajectories->reserve(init_trk_params->size()); //// Construct a perigee surface as the target surface - auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3D{0., 0., 0.}); + auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3{0., 0., 0.}); ACTS_LOCAL_LOGGER(Acts::getDefaultLogger("TrackFindingAlgorithm Logger", Acts::Logging::INFO)); @@ -104,13 +106,14 @@ namespace Jug::Reco { Acts::PropagatorPlainOptions pOptions; pOptions.maxSteps = 10000; + // Set the CombinatorialKalmanFilter options - CKFOptions ckfOptions(m_geoctx, m_fieldctx, m_calibctx, m_sourcelinkSelectorCfg, - Acts::LoggerWrapper{logger()}, pOptions, - &(*pSurface)); + TrackFindingAlgorithm::TrackFinderOptions options( + m_geoctx, m_fieldctx, m_calibctx, MeasurementCalibrator(*measurements), + Acts::CKFSourceLinkSelector(m_sourcelinkSelectorCfg), Acts::LoggerWrapper{logger()}, pOptions, &(*pSurface)); debug() << "Invoke track finding seeded by truth particle " << iseed << endmsg; - auto result = findTracks(*src_links, initialParams, ckfOptions); + auto result = m_trackFinderFunc(*src_links, initialParams, options); debug() << "finding done." << endmsg; if (result.ok()) { // Get the track finding output object @@ -122,7 +125,7 @@ namespace Jug::Reco { debug() << "Track finding failed for truth seed " << iseed << endmsg; ACTS_WARNING("Track finding failed for truth seed " << iseed << " with error" << result.error()); // Track finding failed, but still create an empty SimMultiTrajectory - //trajectories->push_back(SimMultiTrajectory()); + // trajectories->push_back(SimMultiTrajectory()); } } @@ -141,8 +144,9 @@ namespace { TrackFinderFunctionImpl(TrackFinder&& f) : trackFinder(std::move(f)) {} Jug::Reco::TrackFindingAlgorithm::TrackFinderResult - operator()(const Jug::SourceLinkContainer& sourceLinks, const Jug::TrackParameters& initialParameters, - const Acts::CombinatorialKalmanFilterOptions<Acts::CKFSourceLinkSelector>& options) const { + operator()(const Jug::IndexSourceLinkContainer& sourceLinks, const Jug::TrackParameters& initialParameters, + const Jug::Reco::TrackFindingAlgorithm::TrackFinderOptions& options) const + { return trackFinder.findTracks(sourceLinks, initialParameters, options); }; }; @@ -169,7 +173,7 @@ namespace Jug::Reco { using Navigator = Acts::Navigator; using Propagator = Acts::Propagator<Stepper, Navigator>; using SourceLinkSelector = Acts::CKFSourceLinkSelector; - using CKF = Acts::CombinatorialKalmanFilter<Propagator, Updater, Smoother, SourceLinkSelector>; + using CKF = Acts::CombinatorialKalmanFilter<Propagator, Updater, Smoother>; std::cout << " finding ...\n"; // construct all components for the track finder @@ -179,14 +183,14 @@ namespace Jug::Reco { navigator.resolvePassive = false; navigator.resolveMaterial = true; navigator.resolveSensitive = true; - std::cout << " propagator\n" ; + std::cout << " propagator\n"; Propagator propagator(std::move(stepper), std::move(navigator)); CKF trackFinder(std::move(propagator)); + // build the track finder functions. owns the track finder object. return TrackFinderFunctionImpl<CKF>(std::move(trackFinder)); }, std::move(magneticField)); } } // namespace Jug::Reco - diff --git a/JugReco/src/components/TrackFindingAlgorithm.h b/JugReco/src/components/TrackFindingAlgorithm.h index 73d5054da23f1995dab5600dadc0ab1d001ef464..47cd1dc3dd5be7ee6180f736f5954dd9dc634eae 100644 --- a/JugReco/src/components/TrackFindingAlgorithm.h +++ b/JugReco/src/components/TrackFindingAlgorithm.h @@ -16,7 +16,7 @@ //#include "Acts/Geometry/TrackingGeometry.hpp" //#include "Acts/Plugins/DD4hep/DD4hepDetectorElement.hpp" -//#include "Acts/Utilities/Definitions.hpp" +//#include "Acts/Definitions/Common.hpp" //#include "Acts/Utilities/Helpers.hpp" //#include "Acts/Utilities/Logger.hpp" @@ -24,9 +24,11 @@ #include <stdexcept> #include <vector> -#include "JugReco/SourceLinks.h" +#include "JugReco/Index.hpp" +#include "JugReco/IndexSourceLink.hpp" #include "JugReco/Track.hpp" #include "JugReco/BField.h" +#include "JugReco/Measurement.hpp" #include "eicd/TrackerHitCollection.h" @@ -34,17 +36,12 @@ #include "Acts/Geometry/TrackingGeometry.hpp" #include "Acts/TrackFinding/CKFSourceLinkSelector.hpp" #include "Acts/TrackFinding/CombinatorialKalmanFilter.hpp" -#include "Acts/Utilities/Definitions.hpp" - -//#include "Acts/Fitter/GainMatrixSmoother.hpp" -//#include "Acts/Fitter/GainMatrixUpdater.hpp" -//#include "Acts/MagneticField/ConstantBField.hpp" -//#include "Acts/MagneticField/InterpolatedBFieldMap.hpp" -//#include "Acts/MagneticField/SharedBField.hpp" -//#include "Acts/Propagator/EigenStepper.hpp" -//#include "Acts/Propagator/Navigator.hpp" -//#include "Acts/Propagator/Propagator.hpp" -//#include "Acts/Utilities/Units.hpp" +#include "Acts/Definitions/Common.hpp" + +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/TrackFinding/CKFSourceLinkSelector.hpp" +#include "Acts/TrackFinding/CombinatorialKalmanFilter.hpp" + #include <random> #include <stdexcept> @@ -53,17 +50,23 @@ namespace Jug::Reco { class TrackFindingAlgorithm : public GaudiAlgorithm { public: - using TrackFinderResult = Acts::Result<Acts::CombinatorialKalmanFilterResult<SourceLink>>; - - /// Track finding function that takes input measurements, initial trackstate - /// and track finder options and returns some track-finding-specific result. - using CKFOptions = Acts::CombinatorialKalmanFilterOptions<Acts::CKFSourceLinkSelector>; - - using TrackFinderFunction = - std::function<TrackFinderResult(const SourceLinkContainer&, const TrackParameters&, const CKFOptions&)>; + /// Track finder function that takes input measurements, initial trackstate + /// and track finder options and returns some track-finder-specific result. + using TrackFinderOptions = Acts::CombinatorialKalmanFilterOptions<MeasurementCalibrator, Acts::CKFSourceLinkSelector>; + using TrackFinderResult = Acts::Result<Acts::CombinatorialKalmanFilterResult<IndexSourceLink>>; + using TrackFinderFunction = std::function<TrackFinderResult( + const IndexSourceLinkContainer&, const TrackParameters&, const TrackFinderOptions&)>; + + /// Create the track finder function implementation. + /// + /// The magnetic field is intentionally given by-value since the variant + /// contains shared_ptr anyways. + static TrackFinderFunction makeTrackFinderFunction(std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, + BFieldVariant magneticField); public: - DataHandle<SourceLinkContainer> m_inputSourceLinks{"inputSourceLinks", Gaudi::DataHandle::Reader, this}; + DataHandle<IndexSourceLinkContainer> m_inputSourceLinks{"inputSourceLinks", Gaudi::DataHandle::Reader, this}; + DataHandle<MeasurementContainer> m_inputMeasurements{"inputMeasurements", Gaudi::DataHandle::Reader, this}; DataHandle<TrackParametersContainer> m_inputInitialTrackParameters{"inputInitialTrackParameters", Gaudi::DataHandle::Reader, this}; DataHandle<TrajectoryContainer> m_outputTrajectories{"outputTrajectories", Gaudi::DataHandle::Writer, this}; @@ -79,15 +82,7 @@ namespace Jug::Reco { TrackFindingAlgorithm(const std::string& name, ISvcLocator* svcLoc); - /** Create the track finder function implementation. - * The magnetic field is intentionally given by-value since the variant - * contains shared_ptr anyways. - */ - static TrackFinderFunction makeTrackFinderFunction(std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, - BFieldVariant magneticField); - /// Type erased track finder function. - TrackFinderFunction findTracks; StatusCode initialize() override; diff --git a/JugReco/src/components/TrackFittingAlgorithm.cpp b/JugReco/src/components/TrackFittingAlgorithm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2a2d327a17687f00d5156f723a6b7e739068691f --- /dev/null +++ b/JugReco/src/components/TrackFittingAlgorithm.cpp @@ -0,0 +1,199 @@ +// +#include "TrackFittingAlgorithm.h" + +// Gaudi +#include "GaudiAlg/GaudiAlgorithm.h" +#include "GaudiKernel/ToolHandle.h" +#include "GaudiAlg/Transformer.h" +#include "GaudiAlg/GaudiTool.h" +#include "GaudiKernel/RndmGenerators.h" +#include "GaudiKernel/Property.h" + +#include "DDRec/CellIDPositionConverter.h" +#include "DDRec/SurfaceManager.h" +#include "DDRec/Surface.h" + +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/Plugins/DD4hep/DD4hepDetectorElement.hpp" +#include "Acts/Surfaces/PerigeeSurface.hpp" +#include "Acts/MagneticField/ConstantBField.hpp" +#include "Acts/MagneticField/InterpolatedBFieldMap.hpp" +#include "Acts/MagneticField/SharedBField.hpp" +#include "Acts/Propagator/EigenStepper.hpp" +#include "Acts/Propagator/Navigator.hpp" +#include "Acts/Propagator/Propagator.hpp" +#include "Acts/Definitions/Common.hpp" +#include "Acts/Utilities/Helpers.hpp" +#include "Acts/Utilities/Logger.hpp" +#include "Acts/Definitions/Units.hpp" + +#include "JugBase/DataHandle.h" +#include "JugBase/IGeoSvc.h" +#include "JugReco/GeometryContainers.hpp" +#include "JugReco/SourceLinks.h" +#include "JugReco/Track.hpp" +#include "JugReco/BField.h" +#include "JugReco/Measurement.hpp" +#include "JugReco/SourceLinks.h" + +#include "eicd/TrackerHitCollection.h" + +#include <functional> +#include <stdexcept> +#include <vector> +#include <random> +#include <stdexcept> + +namespace Jug::Reco { + + using namespace Acts::UnitLiterals; + + TrackFittingAlgorithm::TrackFittingAlgorithm(const std::string& name, ISvcLocator* svcLoc) + : GaudiAlgorithm(name, svcLoc) + { + declareProperty("inputSourceLinks", m_inputSourceLinks, ""); + declareProperty("initialTrackParameters", m_initialTrackParameters, ""); + declareProperty("foundTracks", m_foundTracks, ""); + declareProperty("outputTrajectories", m_outputTrajectories, ""); + } + + StatusCode TrackFittingAlgorithm::initialize() + { + if (GaudiAlgorithm::initialize().isFailure()) + return StatusCode::FAILURE; + m_geoSvc = service("GeoSvc"); + if (!m_geoSvc) { + error() << "Unable to locate Geometry Service. " + << "Make sure you have GeoSvc and SimSvc in the right order in the configuration." << endmsg; + return StatusCode::FAILURE; + } + m_BField = std::make_shared<Acts::ConstantBField>(Acts::Vector3{0.0, 0.0, m_geoSvc->centralMagneticField()}); + m_fieldctx = BFieldVariant(m_BField); + // chi2 and #sourclinks per surface cutoffs + //m_sourcelinkSelectorCfg = { + // {Acts::GeometryIdentifier(), {15, 10}}, + //}; + m_trackFittingFunc = makeTrackFittingFunction(m_geoSvc->trackingGeometry(), m_BField); + return StatusCode::SUCCESS; + } + + StatusCode TrackFittingAlgorithm::execute() + { + // Read input data + const SourceLinkContainer* src_links = m_inputSourceLinks.get(); + const TrackParametersContainer* init_trk_params = m_initialTrackParameters.get(); + + // TrajectoryContainer trajectories; + auto trajectories = m_outputTrajectories.createAndPut(); + trajectories->reserve(init_trk_params->size()); + + //// Construct a perigee surface as the target surface + auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3{0., 0., 0.}); + ACTS_LOCAL_LOGGER(Acts::getDefaultLogger("TrackFittingAlgorithm Logger", Acts::Logging::INFO)); + + // Perform the track finding for each starting parameter + // @TODO: use seeds from track seeding algorithm as starting parameter + for (std::size_t iseed = 0; iseed < init_trk_params->size(); ++iseed) { + + const auto& initialParams = (*init_trk_params)[iseed]; + Acts::PropagatorPlainOptions pOptions; + pOptions.maxSteps = 10000; + + Acts::KalmanFitterOptions<Acts::VoidOutlierFinder> kfOptions( + m_geoctx, m_fieldctx, m_calibctx, + Acts::VoidOutlierFinder(), Acts::LoggerWrapper{logger()}, Acts::PropagatorPlainOptions(), &(*pSurface)); + + debug() << "Invoke track fitting ... " << iseed << endmsg; + auto result = m_trackFittingFunc(*src_links, initialParams, kfOptions); + debug() << "fitting done." << endmsg; + if (result.ok()) { + // Get the track finding output object + const auto& trackFindingOutput = result.value(); + // Create a SimMultiTrajectory + trajectories->emplace_back(std::move(trackFindingOutput.fittedStates), std::move(trackFindingOutput.trackTips), + std::move(trackFindingOutput.fittedParameters)); + } else { + debug() << "Track finding failed for truth seed " << iseed << endmsg; + ACTS_WARNING("Track finding failed for truth seed " << iseed << " with error" << result.error()); + // Track finding failed, but still create an empty SimMultiTrajectory + // trajectories->push_back(SimMultiTrajectory()); + } + } + + // ctx.eventStore.add(m_cfg.outputTrajectories, std::move(trajectories)); + return StatusCode::SUCCESS; + + + /////////////////////////// + // acts example + + // Set the KalmanFitter options + + // Perform the fit for each input track + //std::vector<IndexSourceLink> trackSourceLinks; + //for (std::size_t itrack = 0; itrack < protoTracks.size(); ++itrack) { + // // The list of hits and the initial start parameters + // const auto& protoTrack = protoTracks[itrack]; + // const auto& initialParams = initialParameters[itrack]; + + // // We can have empty tracks which must give empty fit results so the number + // // of entries in input and output containers matches. + // if (protoTrack.empty()) { + // trajectories.push_back(Trajectories()); + // ACTS_WARNING("Empty track " << itrack << " found."); + // continue; + // } + + // // Clear & reserve the right size + // trackSourceLinks.clear(); + // trackSourceLinks.reserve(protoTrack.size()); + + // // Fill the source links via their indices from the container + // for (auto hitIndex : protoTrack) { + // auto sourceLink = sourceLinks.nth(hitIndex); + // if (sourceLink == sourceLinks.end()) { + // ACTS_FATAL("Proto track " << itrack << " contains invalid hit index" + // << hitIndex); + // return ProcessCode::ABORT; + // } + // trackSourceLinks.push_back(*sourceLink); + // } + + // ACTS_DEBUG("Invoke fitter"); + // auto result = m_cfg.fit(trackSourceLinks, initialParams, kfOptions); + // if (result.ok()) { + // // Get the fit output object + // const auto& fitOutput = result.value(); + // // The track entry indices container. One element here. + // std::vector<size_t> trackTips; + // trackTips.reserve(1); + // trackTips.emplace_back(fitOutput.trackTip); + // // The fitted parameters container. One element (at most) here. + // Trajectories::IndexedParameters indexedParams; + // if (fitOutput.fittedParameters) { + // const auto& params = fitOutput.fittedParameters.value(); + // ACTS_VERBOSE("Fitted paramemeters for track " << itrack); + // ACTS_VERBOSE(" " << params.parameters().transpose()); + // // Push the fitted parameters to the container + // indexedParams.emplace(fitOutput.trackTip, std::move(params)); + // } else { + // ACTS_DEBUG("No fitted paramemeters for track " << itrack); + // } + // // store the result + // trajectories.emplace_back(std::move(fitOutput.fittedStates), + // std::move(trackTips), std::move(indexedParams)); + // } else { + // ACTS_WARNING("Fit failed for track " << itrack << " with error" + // << result.error()); + // // Fit failed. Add an empty result so the output container has + // // the same number of entries as the input. + // trajectories.push_back(Trajectories()); + // } + //} + + + return StatusCode::SUCCESS; + } + + DECLARE_COMPONENT(TrackFittingAlgorithm) +} // namespace Jug::Reco diff --git a/JugReco/src/components/TrackFittingAlgorithm.h b/JugReco/src/components/TrackFittingAlgorithm.h new file mode 100644 index 0000000000000000000000000000000000000000..1386598b1b49d29744ce8f8a9a4f51a1fab4ab62 --- /dev/null +++ b/JugReco/src/components/TrackFittingAlgorithm.h @@ -0,0 +1,110 @@ +#ifndef JUGGLER_JUGRECO_TrackFittingAlgorithm_HH +#define JUGGLER_JUGRECO_TrackFittingAlgorithm_HH + +#include "JugReco/GeometryContainers.hpp" + +// Gaudi +#include "GaudiAlg/GaudiAlgorithm.h" +#include "GaudiKernel/ToolHandle.h" +//#include "GaudiAlg/Transformer.h" +//#include "GaudiAlg/GaudiTool.h" +//#include "GaudiKernel/RndmGenerators.h" +#include "Gaudi/Property.h" + +#include "JugBase/DataHandle.h" +#include "JugBase/IGeoSvc.h" + +//#include "Acts/Geometry/TrackingGeometry.hpp" +//#include "Acts/Plugins/DD4hep/DD4hepDetectorElement.hpp" +//#include "Acts/Definitions/Common.hpp" +//#include "Acts/Utilities/Helpers.hpp" +//#include "Acts/Utilities/Logger.hpp" + +#include <functional> +#include <stdexcept> +#include <vector> + +#include "JugReco/SourceLinks.h" +#include "JugReco/Track.hpp" +#include "JugReco/BField.h" +#include "JugReco/Measurement.hpp" + +#include "eicd/TrackerHitCollection.h" + +//#include "Acts/Surfaces/PerigeeSurface.hpp" + +#include "Acts/TrackFitting/KalmanFitter.hpp" +#include "Acts/TrackFitting/GainMatrixSmoother.hpp" +#include "Acts/TrackFitting/GainMatrixUpdater.hpp" +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/Definitions/Common.hpp" + +//#include "Acts/Fitter/GainMatrixSmoother.hpp" +//#include "Acts/Fitter/GainMatrixUpdater.hpp" +//#include "Acts/MagneticField/ConstantBField.hpp" +//#include "Acts/MagneticField/InterpolatedBFieldMap.hpp" +//#include "Acts/MagneticField/SharedBField.hpp" +//#include "Acts/Propagator/EigenStepper.hpp" +//#include "Acts/Propagator/Navigator.hpp" +//#include "Acts/Propagator/Propagator.hpp" +//#include "Acts/Definitions/Units.hpp" + +#include <random> +#include <stdexcept> + +namespace Jug::Reco { + + class TrackFittingAlgorithm : public GaudiAlgorithm { + public: + //using TrackFinderResult = Acts::Result<Acts::CombinatorialKalmanFilterResult<SourceLink>>; + using FitterResult = Acts::Result<Acts::KalmanFitterResult<SourceLink>>; + /// Fit function that takes input measurements, initial trackstate and fitter + + using FitterFunction = std::function<FitterResult( + const std::vector<SourceLink>&, const TrackParameters&, + const Acts::KalmanFitterOptions<Acts::VoidOutlierFinder>&)>; + + + /// Track fitter function that takes input measurements, initial trackstate + /// and fitter options and returns some track-fitter-specific result. + using TrackFitterOptions = + Acts::KalmanFitterOptions< Acts::VoidOutlierFinder>; + using TrackFitterResult = + Acts::Result<Acts::KalmanFitterResult<SourceLink>>; + using TrackFitterFunction = std::function<TrackFitterResult( + const std::vector<SourceLink>&, const TrackParameters&, + const TrackFitterOptions&)>; + + public: + DataHandle<SourceLinkContainer> m_inputSourceLinks{"inputSourceLinks", Gaudi::DataHandle::Reader, this}; + DataHandle<TrackParametersContainer> m_initialTrackParameters{"initialTrackParameters", Gaudi::DataHandle::Reader, this}; + DataHandle<TrajectoryContainer> m_foundTracks{"foundTracks", Gaudi::DataHandle::Reader, this}; + DataHandle<TrajectoryContainer> m_outputTrajectories{"outputTrajectories", Gaudi::DataHandle::Writer, this}; + + FitterFunction m_trackFittingFunc; + SmartIF<IGeoSvc> m_geoSvc; + std::shared_ptr<Acts::ConstantBField> m_BField = nullptr; + Acts::GeometryContext m_geoctx; + Acts::CalibrationContext m_calibctx; + Acts::MagneticFieldContext m_fieldctx; + + //Acts::CKFSourceLinkSelector::Config m_sourcelinkSelectorCfg; + + TrackFittingAlgorithm(const std::string& name, ISvcLocator* svcLoc); + + /** Create the track finder function implementation. + * The magnetic field is intentionally given by-value since the variant + * contains shared_ptr anyways. + */ + static FitterFunction makeTrackFittingFunction(std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, + BFieldVariant magneticField); + + + StatusCode initialize() override; + + StatusCode execute() override; + }; + +} // namespace Jug::Reco + +#endif diff --git a/JugReco/src/components/TrackFittingFunction.cpp b/JugReco/src/components/TrackFittingFunction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9eafb46ffba71f01639e3a6368322266e9d02bc8 --- /dev/null +++ b/JugReco/src/components/TrackFittingFunction.cpp @@ -0,0 +1,77 @@ +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/MagneticField/ConstantBField.hpp" +#include "Acts/MagneticField/InterpolatedBFieldMap.hpp" +#include "Acts/MagneticField/SharedBField.hpp" +#include "Acts/Propagator/EigenStepper.hpp" +#include "Acts/Propagator/Navigator.hpp" +#include "Acts/Propagator/Propagator.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "Acts/TrackFitting/GainMatrixSmoother.hpp" +#include "Acts/TrackFitting/GainMatrixUpdater.hpp" +#include "Acts/Utilities/Helpers.hpp" +#include "Acts/Utilities/ParameterDefinitions.hpp" +//#include "ActsExamples/Plugins/BField/ScalableBField.hpp" +#include "TrackFittingAlgorithm.h" + +namespace { + + template <typename track_fitter_t> + struct TrackFitterFunctionImpl { + track_fitter_t trackFitter; + + TrackFitterFunctionImpl(track_fitter_t&& f) : trackFitter(std::move(f)) {} + + Jug::Reco::TrackFittingAlgorithm::FitterResult operator()( + const std::vector<Jug::SourceLink>& sourceLinks, + const Jug::TrackParameters& initialParameters, + const Acts::KalmanFitterOptions<Acts::VoidOutlierFinder>& options) const { + return fitter.fit(sourceLinks, initialParameters, options); + } + + //TrackFittingAlgorithm::TrackFitterResult + //operator()(const std::vector<SourceLink>& sourceLinks, + // const TrackParameters& initialParameters, + // const TrackFittingAlgorithm::TrackFitterOptions& options) const + //{ + // return trackFitter.fit(sourceLinks, initialParameters, options); + //}; + }; + +} // namespace + +namespace Jug::Reco { + TrackFittingAlgorithm::TrackFitterFunction TrackFittingAlgorithm::makeTrackFittingFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, Options::BFieldVariant magneticField) + { + using Updater = Acts::GainMatrixUpdater; + using Smoother = Acts::GainMatrixSmoother; + + // unpack the magnetic field variant and instantiate the corresponding fitter. + return std::visit( + [trackingGeometry](auto&& inputField) -> TrackFitterFunction { + // each entry in the variant is already a shared_ptr + // need ::element_type to get the real magnetic field type + using InputMagneticField = typename std::decay_t<decltype(inputField)>::element_type; + using MagneticField = Acts::SharedBField<InputMagneticField>; + using Stepper = Acts::EigenStepper<MagneticField>; + using Navigator = Acts::Navigator; + using Propagator = Acts::Propagator<Stepper, Navigator>; + using Fitter = Acts::KalmanFitter<Propagator, Updater, Smoother>; + + // construct all components for the fitter + MagneticField field(std::move(inputField)); + Stepper stepper(std::move(field)); + Navigator navigator(trackingGeometry); + navigator.resolvePassive = false; + navigator.resolveMaterial = true; + navigator.resolveSensitive = true; + Propagator propagator(std::move(stepper), std::move(navigator)); + Fitter trackFitter(std::move(propagator)); + + // build the fitter functions. owns the fitter object. + return TrackFitterFunctionImpl<Fitter>(std::move(trackFitter)); + }, + std::move(magneticField)); + } +} // namespace Jug::Reco diff --git a/JugReco/src/components/TrackParamClusterInit.cpp b/JugReco/src/components/TrackParamClusterInit.cpp index cd8010fdbae0db107de627e6fde213aeb6e66995..a9715615fabdb3002997c7c3c0313a21b9338c3b 100644 --- a/JugReco/src/components/TrackParamClusterInit.cpp +++ b/JugReco/src/components/TrackParamClusterInit.cpp @@ -10,12 +10,14 @@ #include "JugBase/DataHandle.h" #include "JugBase/IGeoSvc.h" #include "JugReco/Track.hpp" -#include "Acts/Utilities/Units.hpp" -#include "Acts/Utilities/Definitions.hpp" +#include "Acts/Definitions/Units.hpp" +#include "Acts/Definitions/Common.hpp" #include "eicd/TrackerHitCollection.h" #include "eicd/ClusterCollection.h" +#include "Math/Vector3D.h" +#include "Acts/Surfaces/PerigeeSurface.hpp" ///// (Reconstructed) track parameters e.g. close to the vertex. //using TrackParameters = Acts::CurvilinearTrackParameters; @@ -77,28 +79,52 @@ namespace Jug::Reco { continue; } double len = std::hypot( c.x() , c.y() , c.z() ); + ROOT::Math::XYZVector momentum(c.x() * p / len, c.y() * p / len, c.z() * p / len); // build some track cov matrix - Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero(); - cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = 1.0 * mm*1.0 * mm; - cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = 1.0 * mm*1.0 * mm; - cov(Acts::eBoundPhi, Acts::eBoundPhi) = M_PI / 180.0; - cov(Acts::eBoundTheta, Acts::eBoundTheta) = M_PI / 180.0; - cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = 1.0 / (p*p); - cov(Acts::eBoundTime, Acts::eBoundTime) = Acts::UnitConstants::ns; + //Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero(); + //cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = 1.0 * mm*1.0 * mm; + //cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = 1.0 * mm*1.0 * mm; + //cov(Acts::eBoundPhi, Acts::eBoundPhi) = M_PI / 180.0; + //cov(Acts::eBoundTheta, Acts::eBoundTheta) = M_PI / 180.0; + //cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = 1.0 / (p*p); + //cov(Acts::eBoundTime, Acts::eBoundTime) = Acts::UnitConstants::ns; + + Acts::BoundVector params; + params(Acts::eBoundLoc0) = 0.0 * mm ; + params(Acts::eBoundLoc1) = 0.0 * mm ; + params(Acts::eBoundPhi) = momentum.Phi(); + params(Acts::eBoundTheta) = momentum.Theta(); + params(Acts::eBoundQOverP) = 1/p; + params(Acts::eBoundTime) = 0 * ns; + + auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3{0,0,0}); debug() << "Invoke track finding seeded by truth particle with p = " << p/GeV << " GeV" << endmsg; - // add all charges to the track candidate... - init_trk_params->emplace_back(Acts::Vector4D(0 * mm, 0 * mm, 0 * mm, 0), - Acts::Vector3D(c.x() * p / len, c.y() * p / len, c.z() * p / len), p, -1, - std::make_optional(cov)); - debug() << init_trk_params->back() << endmsg; - init_trk_params->emplace_back(Acts::Vector4D(0 * mm, 0 * mm, 0 * mm, 0), - Acts::Vector3D(c.x() * p / len, c.y() * p / len, c.z() * p / len), p, 1, - std::make_optional(cov)); - debug() << init_trk_params->back() << endmsg; - //init_trk_params->emplace_back(Acts::Vector4D(0 * mm, 0 * mm, 0 * mm, 0), - // Acts::Vector3D(c.x() * p / len, c.y() * p / len, c.z() * p / len), p, 0, + + // add both charges to the track candidate... + init_trk_params->push_back({pSurface, params, 1}); + + Acts::BoundVector params2; + params2(Acts::eBoundLoc0) = 0.0 * mm ; + params2(Acts::eBoundLoc1) = 0.0 * mm ; + params2(Acts::eBoundPhi) = momentum.Phi(); + params2(Acts::eBoundTheta) = momentum.Theta(); + params2(Acts::eBoundQOverP) = -1/p; + params2(Acts::eBoundTime) = 0 * ns; + init_trk_params->push_back({pSurface, params2, -1}); + + // acts v1.2.0: + //init_trk_params->emplace_back(Acts::Vector4(0 * mm, 0 * mm, 0 * mm, 0), + // Acts::Vector3(c.x() * p / len, c.y() * p / len, c.z() * p / len), p, -1, + // std::make_optional(cov)); + //debug() << init_trk_params->back() << endmsg; + //init_trk_params->emplace_back(Acts::Vector4(0 * mm, 0 * mm, 0 * mm, 0), + // Acts::Vector3(c.x() * p / len, c.y() * p / len, c.z() * p / len), p, 1, + // std::make_optional(cov)); + ////debug() << init_trk_params->back() << endmsg; + //init_trk_params->emplace_back(Acts::Vector4(0 * mm, 0 * mm, 0 * mm, 0), + // Acts::Vector3(c.x() * p / len, c.y() * p / len, c.z() * p / len), p, 0, // std::make_optional(cov)); } return StatusCode::SUCCESS; diff --git a/JugReco/src/components/TrackParamTruthInit.cpp b/JugReco/src/components/TrackParamTruthInit.cpp index f12c86aeb5f462e6d4eacd164e7c21df5cd26d8c..34a8077c57454a72d7370056b3a77ec9aec86eef 100644 --- a/JugReco/src/components/TrackParamTruthInit.cpp +++ b/JugReco/src/components/TrackParamTruthInit.cpp @@ -10,11 +10,13 @@ #include "JugBase/DataHandle.h" #include "JugBase/IGeoSvc.h" #include "JugReco/Track.hpp" -#include "Acts/Utilities/Units.hpp" -#include "Acts/Utilities/Definitions.hpp" +#include "Acts/Definitions/Units.hpp" +#include "Acts/Definitions/Common.hpp" #include "eicd/TrackerHitCollection.h" #include "dd4pod/Geant4ParticleCollection.h" +#include "Math/Vector3D.h" +#include "Acts/Surfaces/PerigeeSurface.hpp" ///// (Reconstructed) track parameters e.g. close to the vertex. @@ -70,11 +72,13 @@ namespace Jug::Reco { if(part.genStatus() != 1 ) { continue; } - using Acts::UnitConstants::MeV; using Acts::UnitConstants::GeV; + using Acts::UnitConstants::MeV; using Acts::UnitConstants::mm; + using Acts::UnitConstants::ns; double p = std::hypot( part.psx() * GeV, part.psy() * GeV, part.psz() * GeV); + ROOT::Math::XYZVector momentum(part.psx() * GeV, part.psy() * GeV, part.psz() * GeV); // build some track cov matrix Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero(); @@ -83,15 +87,30 @@ namespace Jug::Reco { cov(Acts::eBoundPhi, Acts::eBoundPhi) = M_PI / 180.0; cov(Acts::eBoundTheta, Acts::eBoundTheta) = M_PI / 180.0; cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = 0.98 / (p*p); - cov(Acts::eBoundTime, Acts::eBoundTime) = Acts::UnitConstants::ns; - - init_trk_params->emplace_back(Acts::Vector4D(part.vsx() * mm, part.vsy() * mm, part.vsz() * mm, part.time() * Acts::UnitConstants::ns), - Acts::Vector3D(part.psx() * GeV, part.psy() * GeV, part.psz() * GeV), - p+200*MeV, - ((part.pdgID() > 0) ? -1 : 1), - std::make_optional(std::move(cov)) - ); - //part .charge() + cov(Acts::eBoundTime, Acts::eBoundTime) = 1.0*ns; + + Acts::BoundVector params; + params(Acts::eBoundLoc0) = 0.0 * mm ; // cylinder radius + params(Acts::eBoundLoc1) = 0.0 * mm ; // cylinder length + params(Acts::eBoundPhi) = momentum.Phi(); + params(Acts::eBoundTheta) = momentum.Theta(); + params(Acts::eBoundQOverP) = 1/p; + params(Acts::eBoundTime) = part.time() * ns; + /// \todo create or find better particle data interface. + // get the particle charge + int charge = ((part.pdgID() > 0) ? 1 : -1); + // electron is negative but positive pdg code + if( std::abs(part.pdgID()) == 11 ) { + charge *= -1; + } + + //// Construct a perigee surface as the target surface + auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>( + Acts::Vector3{part.vsx() * mm, part.vsy() * mm, part.vsz() * mm}); + + params(Acts::eBoundQOverP) = charge/p; + init_trk_params->push_back({pSurface, params, charge}); + // std::make_optional(std::move(cov)) debug() << "Invoke track finding seeded by truth particle with p = " << p/GeV << " GeV" << endmsg; //Acts::BoundMatrix cov = Acts::BoundMatrix::Zero(); diff --git a/JugReco/src/components/TrackParamVertexClusterInit.cpp b/JugReco/src/components/TrackParamVertexClusterInit.cpp index 9b9fc91471f05dcf3f6eee3c815c625932cdb306..9855071d1594a963cb9f4f14099c2a6ff5429bff 100644 --- a/JugReco/src/components/TrackParamVertexClusterInit.cpp +++ b/JugReco/src/components/TrackParamVertexClusterInit.cpp @@ -12,11 +12,13 @@ #include "JugBase/DataHandle.h" #include "JugBase/IGeoSvc.h" #include "JugReco/Track.hpp" -#include "Acts/Utilities/Units.hpp" -#include "Acts/Utilities/Definitions.hpp" +#include "Acts/Definitions/Units.hpp" +#include "Acts/Definitions/Common.hpp" #include "eicd/TrackerHitCollection.h" #include "eicd/ClusterCollection.h" +#include "Math/Vector3D.h" +#include "Acts/Surfaces/PerigeeSurface.hpp" using namespace Gaudi::Units; @@ -79,6 +81,7 @@ namespace Jug::Reco { continue; } + auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3{0,0,0}); for (const auto& t : *vtx_hits) { double len = std::hypot(t.x(), t.y(), t.z()); @@ -86,30 +89,54 @@ namespace Jug::Reco { continue; } - // build some track cov matrix - Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero(); - cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = 1.0 * mm*1.0 * mm; - cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = 1.0 * mm*1.0 * mm; - cov(Acts::eBoundPhi, Acts::eBoundPhi) = M_PI / 180.0; - cov(Acts::eBoundTheta, Acts::eBoundTheta) = M_PI / 180.0; - cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = 1.0 / (0.9*0.9*p_cluster*p_cluster); - cov(Acts::eBoundTime, Acts::eBoundTime) = Acts::UnitConstants::ns; - - // add all charges to the track candidate... - init_trk_params->emplace_back(Acts::Vector4D(0 * mm, 0 * mm, 0 * mm, 0), - Acts::Vector3D(t.x() * p_cluster / len, t.y() * p_cluster / len, t.z() * p_cluster / len), p_cluster, -1, - std::make_optional(cov)); - init_trk_params->emplace_back(Acts::Vector4D(0 * mm, 0 * mm, 0 * mm, 0), - Acts::Vector3D(t.x() * p_cluster / len, t.y() * p_cluster / len, t.z() * p_cluster / len), p_cluster, 1, - std::make_optional(cov)); + //// build some track cov matrix + //Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero(); + //cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = 1.0 * mm*1.0 * mm; + //cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = 1.0 * mm*1.0 * mm; + //cov(Acts::eBoundPhi, Acts::eBoundPhi) = M_PI / 180.0; + //cov(Acts::eBoundTheta, Acts::eBoundTheta) = M_PI / 180.0; + //cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = 1.0 / (0.9*0.9*p_cluster*p_cluster); + //cov(Acts::eBoundTime, Acts::eBoundTime) = Acts::UnitConstants::ns; + + //// add all charges to the track candidate... + //init_trk_params->emplace_back(Acts::Vector4(0 * mm, 0 * mm, 0 * mm, 0), + // Acts::Vector3(t.x() * p_cluster / len, t.y() * p_cluster / len, t.z() * p_cluster / len), p_cluster, -1, + // std::make_optional(cov)); + //init_trk_params->emplace_back(Acts::Vector4(0 * mm, 0 * mm, 0 * mm, 0), + // Acts::Vector3(t.x() * p_cluster / len, t.y() * p_cluster / len, t.z() * p_cluster / len), p_cluster, 1, + // std::make_optional(cov)); + + ROOT::Math::XYZVector momentum(t.x() * p_cluster / len, t.y() * p_cluster / len, t.z() * p_cluster / len); + + Acts::BoundVector params; + params(Acts::eBoundLoc0) = 0.0 * mm; + params(Acts::eBoundLoc1) = 0.0 * mm; + params(Acts::eBoundPhi) = momentum.Phi(); + params(Acts::eBoundTheta) = momentum.Theta(); + params(Acts::eBoundQOverP) = 1 / p_cluster; + params(Acts::eBoundTime) = 0 * ns; + + //debug() << "Invoke track finding seeded by truth particle with p = " << p / GeV << " GeV" << endmsg; + + // add both charges to the track candidate... + init_trk_params->push_back({pSurface, params, 1}); + + Acts::BoundVector params2; + params2(Acts::eBoundLoc0) = 0.0 * mm; + params2(Acts::eBoundLoc1) = 0.0 * mm; + params2(Acts::eBoundPhi) = momentum.Phi(); + params2(Acts::eBoundTheta) = momentum.Theta(); + params2(Acts::eBoundQOverP) = -1 / p_cluster; + params2(Acts::eBoundTime) = 0 * ns; + init_trk_params->push_back({pSurface, params2, -1}); } - //init_trk_params->emplace_back(Acts::Vector4D(0 * mm, 0 * mm, 0 * mm, 0), - // Acts::Vector3D(c.x() * p / len, c.y() * p / len, c.z() * p / len), p, 1, + // init_trk_params->emplace_back(Acts::Vector4(0 * mm, 0 * mm, 0 * mm, 0), + // Acts::Vector3(c.x() * p / len, c.y() * p / len, c.z() * p / len), p, 1, // std::make_optional(cov)); - //init_trk_params->emplace_back(Acts::Vector4D(0 * mm, 0 * mm, 0 * mm, 0), - // Acts::Vector3D(c.x() * p / len, c.y() * p / len, c.z() * p / len), p, 0, + // init_trk_params->emplace_back(Acts::Vector4(0 * mm, 0 * mm, 0 * mm, 0), + // Acts::Vector3(c.x() * p / len, c.y() * p / len, c.z() * p / len), p, 0, // std::make_optional(cov)); - debug() << "Invoke track finding seeded by truth particle with p = " << p_cluster/GeV << " GeV" << endmsg; + // debug() << "Invoke track finding seeded by truth particle with p = " << p_cluster/GeV << " GeV" << endmsg; } return StatusCode::SUCCESS; } diff --git a/JugReco/src/components/TrackerHitReconstruction.cpp b/JugReco/src/components/TrackerHitReconstruction.cpp index 43e7190f117e72c7bac6b3ff5a21275fe5b38f51..d32c854fe8223e7d0efcf773af079b51cb35e9f5 100644 --- a/JugReco/src/components/TrackerHitReconstruction.cpp +++ b/JugReco/src/components/TrackerHitReconstruction.cpp @@ -2,11 +2,11 @@ // Gaudi #include "GaudiAlg/GaudiAlgorithm.h" -#include "GaudiKernel/ToolHandle.h" +//#include "GaudiKernel/ToolHandle.h" #include "GaudiAlg/Transformer.h" #include "GaudiAlg/GaudiTool.h" #include "GaudiKernel/RndmGenerators.h" -#include "GaudiKernel/Property.h" +#include "Gaudi/Property.h" #include "DDRec/CellIDPositionConverter.h" #include "DDRec/SurfaceManager.h" @@ -20,7 +20,6 @@ //#include "GaudiExamples/MyTrack.h" #include "eicd/RawTrackerHitCollection.h" #include "eicd/TrackerHitCollection.h" -#include "JugReco/SourceLinks.h" #include "DD4hep/DD4hepUnits.h" diff --git a/JugReco/src/components/TrackerSourceLinker.cpp b/JugReco/src/components/TrackerSourceLinker.cpp index 0927d047782006423cde6308f84b25eca47c3a24..8e78cf5ac1a62ab4d60623f67ef68cc6a1c3537e 100644 --- a/JugReco/src/components/TrackerSourceLinker.cpp +++ b/JugReco/src/components/TrackerSourceLinker.cpp @@ -6,7 +6,7 @@ #include "GaudiAlg/Transformer.h" #include "GaudiAlg/GaudiTool.h" #include "GaudiKernel/RndmGenerators.h" -#include "GaudiKernel/Property.h" +#include "Gaudi/Property.h" #include "JugBase/DataHandle.h" #include "JugBase/IGeoSvc.h" @@ -18,12 +18,15 @@ #include "DD4hep/DD4hepUnits.h" -#include "Acts/Utilities/Units.hpp" -#include "Acts/Utilities/Definitions.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "Acts/Definitions/Units.hpp" +#include "Acts/Definitions/Common.hpp" #include "Acts/Geometry/TrackingGeometry.hpp" #include "Acts/Plugins/DD4hep/DD4hepDetectorElement.hpp" -#include "JugReco/SourceLinks.h" +#include "JugReco/Index.hpp" +#include "JugReco/IndexSourceLink.hpp" +#include "JugReco/Measurement.hpp" #include "eicd/TrackerHitCollection.h" @@ -32,7 +35,8 @@ namespace Jug::Reco { class TrackerSourceLinker : public GaudiAlgorithm { public: DataHandle<eic::TrackerHitCollection> m_inputHitCollection{"inputHitCollection", Gaudi::DataHandle::Reader, this}; - DataHandle<SourceLinkContainer> m_outputSourceLinks{"outputSourceLinks", Gaudi::DataHandle::Writer, this}; + DataHandle<IndexSourceLinkContainer> m_outputSourceLinks{"outputSourceLinks", Gaudi::DataHandle::Writer, this}; + DataHandle<MeasurementContainer> m_outputMeasurements{"outputMeasurements", Gaudi::DataHandle::Writer, this}; /// Pointer to the geometry service SmartIF<IGeoSvc> m_geoSvc; @@ -44,6 +48,7 @@ namespace Jug::Reco { : GaudiAlgorithm(name, svcLoc) { declareProperty("inputHitCollection", m_inputHitCollection, ""); declareProperty("outputSourceLinks", m_outputSourceLinks, ""); + declareProperty("outputMeasurements", m_outputMeasurements, ""); } StatusCode initialize() override { @@ -77,60 +82,60 @@ namespace Jug::Reco { // input collection const eic::TrackerHitCollection* hits = m_inputHitCollection.get(); // Create output collections - auto source_links = m_outputSourceLinks.createAndPut(); - // setup local covariance - // TODO add support for per volume/layer/module settings + auto sourceLinks = m_outputSourceLinks.createAndPut(); + auto measurements = m_outputMeasurements.createAndPut(); + // IndexMultimap<ActsFatras::Barcode> hitParticlesMap; + // IndexMultimap<Index> hitSimHitsMap; + sourceLinks->reserve(hits->size()); + measurements->reserve(hits->size()); debug() << (*hits).size() << " hits " << endmsg; + int ihit = 0; for(const auto& ahit : *hits) { - Acts::BoundMatrix cov = Acts::BoundMatrix::Zero(); - cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = ahit.covsym_xx()*Acts::UnitConstants::mm*ahit.covsym_xx()*Acts::UnitConstants::mm; - cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = ahit.covsym_yy()*Acts::UnitConstants::mm*ahit.covsym_yy()*Acts::UnitConstants::mm; + Acts::SymMatrix2 cov = Acts::SymMatrix2::Zero(); + cov(0,0) = ahit.covsym_xx()*Acts::UnitConstants::mm*ahit.covsym_xx()*Acts::UnitConstants::mm; + cov(1,1) = ahit.covsym_yy()*Acts::UnitConstants::mm*ahit.covsym_yy()*Acts::UnitConstants::mm; - auto vol_ctx = m_geoSvc->cellIDPositionConverter()->findContext(ahit.cellID()); - auto vol_id = vol_ctx->identifier; - //debug() << " hit : \n" << ahit << endmsg; - //debug() << "cell ID : " << ahit.cellID() << endmsg; - //debug() << " position : (" << ahit.position(0) << ", " << ahit.position(1) << ", "<< ahit.position(2) << ") " << endmsg; - debug() << " vol_id : " << vol_id << endmsg; - debug() << " placment pos : " << vol_ctx->volumePlacement().position() << endmsg; - - const auto is = m_surfaces.find(vol_id); + auto vol_ctx = m_geoSvc->cellIDPositionConverter()->findContext(ahit.cellID()); + auto vol_id = vol_ctx->identifier; + const auto is = m_surfaces.find(vol_id); if (is == m_surfaces.end()) { debug() << " vol_id (" << vol_id << ") not found in m_surfaces." <<endmsg; continue; } const Acts::Surface* surface = is->second; - debug() << " surface center : " << surface->center(Acts::GeometryContext()) << endmsg; // transform global position into local coordinates - Acts::Vector2D pos(0, 0); + Acts::Vector2 pos(0, 0); // geometry context contains nothing here pos = surface->globalToLocal(Acts::GeometryContext(), {ahit.x(), ahit.y(), ahit.z()}, {0, 0, 0}).value();//, pos); - //// smear truth to create local measurement - Acts::BoundVector loc = Acts::BoundVector::Zero(); + Acts::Vector2 loc = Acts::Vector2::Zero(); loc[Acts::eBoundLoc0] = pos[0] ;//+ m_cfg.sigmaLoc0 * stdNormal(rng); loc[Acts::eBoundLoc1] = pos[1] ;//+ m_cfg.sigmaLoc1 * stdNormal(rng); + //debug() << "loc : (" << loc[0] << ", " << loc[1] << ")" << endmsg; - debug() << "loc : (" << loc[0] << ", " << loc[1] << ")" << endmsg; + //local position + //auto loc = {ahit.x(), ahit.y(), ahit.z()} - vol_ctx->volumePlacement().position() + //debug() << " hit : \n" << ahit << endmsg; + //debug() << " cell ID : " << ahit.cellID() << endmsg; + //debug() << " position : (" << ahit.position(0) << ", " << ahit.position(1) << ", "<< ahit.position(2) << ") " << endmsg; + //debug() << " vol_id : " << vol_id << endmsg; + //debug() << " placment pos : " << vol_ctx->volumePlacement().position() << endmsg; - // create source link at the end of the container - //auto it = source_links->emplace_hint(source_links->end(), *surface, hit, 2, loc, cov); - auto it = source_links->emplace_hint(source_links->end(), *surface, 2, loc, cov); - // ensure hits and links share the same order to prevent ugly surprises - if (std::next(it) != source_links->end()) { - error() << "The hit ordering broke. Run for your life." << endmsg; - return StatusCode::FAILURE; - } + // the measurement container is unordered and the index under which the + // measurement will be stored is known before adding it. + Index hitIdx = measurements->size(); + IndexSourceLink sourceLink(vol_id, ihit); + auto meas = Acts::makeMeasurement(sourceLink, loc, cov, Acts::eBoundLoc0, Acts::eBoundLoc1); + + // add to output containers. since the input is already geometry-order, + // new elements in geometry containers can just be appended at the end. + sourceLinks->emplace_hint(sourceLinks->end(), std::move(sourceLink)); + measurements->emplace_back(std::move(meas)); - //std::array<double,3> posarr; pos.GetCoordinates(posarr); - //std::array<double,3> dimarr; dim.GetCoordinates(posarr); - //eic::TrackerHit hit; - //eic::TrackerHit hit((long long)ahit.cellID0(), (long long)ahit.cellID(), (long long)ahit.time(), - // (float)ahit.charge() / 10000.0, (float)0.0, {{pos.x(), pos.y(),pos.z()}},{{dim[0],dim[1],0.0}}); - //rec_hits->push_back(hit); + ihit++; } return StatusCode::SUCCESS; } @@ -140,82 +145,3 @@ namespace Jug::Reco { } // namespace Jug::reco -//HitSmearing::HitSmearing(const Config& cfg, Acts::Logging::Level lvl) -// : BareAlgorithm("HitSmearing", lvl), m_cfg(cfg) { -// if (m_cfg.inputSimulatedHits.empty()) { -// throw std::invalid_argument("Missing input simulated hits collection"); -// } -// if (m_cfg.outputSourceLinks.empty()) { -// throw std::invalid_argument("Missing output source links collection"); -// } -// if ((m_cfg.sigmaLoc0 < 0) or (m_cfg.sigmaLoc1 < 0)) { -// throw std::invalid_argument("Invalid resolution setting"); -// } -// if (not m_cfg.trackingGeometry) { -// throw std::invalid_argument("Missing tracking geometry"); -// } -// if (!m_cfg.randomNumbers) { -// throw std::invalid_argument("Missing random numbers tool"); -// } -// // fill the surface map to allow lookup by geometry id only -// m_cfg.trackingGeometry->visitSurfaces([this](const Acts::Surface* surface) { -// // for now we just require a valid surface -// if (not surface) { -// return; -// } -// this->m_surfaces.insert_or_assign(surface->associatedDetectorElement()->identifier(), surface); -// }); -// } -//} - -//ProcessCode HitSmearing::execute(const AlgorithmContext& ctx) const { -// // setup input and output containers -// const auto& hits = -// ctx.eventStore.get<SimHitContainer>(m_cfg.inputSimulatedHits); -// SimSourceLinkContainer sourceLinks; -// sourceLinks.reserve(hits.size()); -// -// // setup random number generator -// auto rng = m_cfg.randomNumbers->spawnGenerator(ctx); -// std::normal_distribution<double> stdNormal(0.0, 1.0); -// -// // setup local covariance -// // TODO add support for per volume/layer/module settings -// Acts::BoundMatrix cov = Acts::BoundMatrix::Zero(); -// cov(Acts::eLOC_0, Acts::eLOC_0) = m_cfg.sigmaLoc0 * m_cfg.sigmaLoc0; -// cov(Acts::eLOC_1, Acts::eLOC_1) = m_cfg.sigmaLoc1 * m_cfg.sigmaLoc1; -// -// for (auto&& [moduleGeoId, moduleHits] : groupByModule(hits)) { -// // check if we should create hits for this surface -// const auto is = m_surfaces.find(moduleGeoId); -// if (is == m_surfaces.end()) { -// continue; -// } -// -// // smear all truth hits for this module -// const Acts::Surface* surface = is->second; -// for (const auto& hit : moduleHits) { -// // transform global position into local coordinates -// Acts::Vector2D pos(0, 0); -// surface->globalToLocal(ctx.geoContext, hit.position(), -// hit.unitDirection(), pos); -// -// // smear truth to create local measurement -// Acts::BoundVector loc = Acts::BoundVector::Zero(); -// loc[Acts::eLOC_0] = pos[0] + m_cfg.sigmaLoc0 * stdNormal(rng); -// loc[Acts::eLOC_1] = pos[1] + m_cfg.sigmaLoc1 * stdNormal(rng); -// -// // create source link at the end of the container -// auto it = sourceLinks.emplace_hint(sourceLinks.end(), *surface, hit, 2, -// loc, cov); -// // ensure hits and links share the same order to prevent ugly surprises -// if (std::next(it) != sourceLinks.end()) { -// ACTS_FATAL("The hit ordering broke. Run for your life."); -// return ProcessCode::ABORT; -// } -// } -// } -// -// ctx.eventStore.add(m_cfg.outputSourceLinks, std::move(sourceLinks)); -// return ProcessCode::SUCCESS; -//} diff --git a/JugReco/src/components/TrackerSourcesLinker.cpp b/JugReco/src/components/TrackerSourcesLinker.cpp index d054487a2c25f00a336034bfc6d02375d8fe6353..c1ab51f2eb661f3335e70c66394222e4cbcfe08a 100644 --- a/JugReco/src/components/TrackerSourcesLinker.cpp +++ b/JugReco/src/components/TrackerSourcesLinker.cpp @@ -1,4 +1,5 @@ #include "JugReco/GeometryContainers.hpp" +#include <ios> // Gaudi #include "GaudiAlg/GaudiAlgorithm.h" @@ -15,15 +16,18 @@ #include "DDRec/SurfaceManager.h" #include "DDRec/Surface.h" #include "DD4hep/Volumes.h" +#include "DD4hep/VolumeManager.h" #include "DD4hep/DD4hepUnits.h" - -#include "Acts/Utilities/Units.hpp" -#include "Acts/Utilities/Definitions.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "Acts/Definitions/Units.hpp" +#include "Acts/Definitions/Common.hpp" #include "Acts/Geometry/TrackingGeometry.hpp" #include "Acts/Plugins/DD4hep/DD4hepDetectorElement.hpp" -#include "JugReco/SourceLinks.h" +#include "JugReco/Index.hpp" +#include "JugReco/IndexSourceLink.hpp" +#include "JugReco/Measurement.hpp" #include "eicd/TrackerHitCollection.h" @@ -38,10 +42,12 @@ namespace Jug::Reco { DataHandle<HitCol> m_ITrackerEndcapHits{"ITrackerEndcapHits", Gaudi::DataHandle::Reader, this}; DataHandle<HitCol> m_OTrackerBarrelHits{"OTrackerBarrelHits", Gaudi::DataHandle::Reader, this}; DataHandle<HitCol> m_OTrackerEndcapHits{"OTrackerEndcapHits", Gaudi::DataHandle::Reader, this}; + DataHandle<HitCol> m_allTrackerHits{"allTrackerHits", Gaudi::DataHandle::Writer, this}; std::vector<DataHandle<HitCol>*> m_trackerHitCollections; //Gaudi::Property<std::vector<std::string>> m_trackerHitCollections{this, "trackerHitCollections"}; - DataHandle<SourceLinkContainer> m_outputSourceLinks{"outputSourceLinks", Gaudi::DataHandle::Writer, this}; + DataHandle<IndexSourceLinkContainer> m_outputSourceLinks{"outputSourceLinks", Gaudi::DataHandle::Writer, this}; + DataHandle<MeasurementContainer> m_outputMeasurements{"outputMeasurements", Gaudi::DataHandle::Writer, this}; /// Pointer to the geometry service SmartIF<IGeoSvc> m_geoSvc; @@ -56,6 +62,8 @@ namespace Jug::Reco { declareProperty("OTrackerBarrelHits", m_OTrackerBarrelHits, ""); declareProperty("OTrackerEndcapHits", m_OTrackerEndcapHits, ""); declareProperty("outputSourceLinks", m_outputSourceLinks, ""); + declareProperty("outputMeasurements", m_outputMeasurements, ""); + declareProperty("allTrackerHits", m_allTrackerHits, ""); } @@ -64,7 +72,7 @@ namespace Jug::Reco { return StatusCode::FAILURE; m_trackerHitCollections.push_back(&m_ITrackerBarrelHits); - m_trackerHitCollections.push_back(&m_ITrackerEndcapHits); + //m_trackerHitCollections.push_back(&m_ITrackerEndcapHits); m_trackerHitCollections.push_back(&m_OTrackerBarrelHits); m_trackerHitCollections.push_back(&m_OTrackerEndcapHits); @@ -86,6 +94,9 @@ namespace Jug::Reco { debug() << "invalid det_element!!! " << endmsg; return; } + if(det_element->identifier() == 542675589) { + debug() << "test volume FOUND!!!!!!!!!!! " << endmsg; + } this->m_surfaces.insert_or_assign(det_element->identifier(), surface); }); @@ -94,67 +105,79 @@ namespace Jug::Reco { StatusCode execute() override { // Create output collections - auto source_links = m_outputSourceLinks.createAndPut(); - // setup local covariance - // TODO add support for per volume/layer/module settings + auto sourceLinks = m_outputSourceLinks.createAndPut(); + auto measurements = m_outputMeasurements.createAndPut(); + auto allHits = m_allTrackerHits.createAndPut(); + // IndexMultimap<ActsFatras::Barcode> hitParticlesMap; + // IndexMultimap<Index> hitSimHitsMap; + //int total_hits = 0; + //for(const auto col : m_trackerHitCollections) { + // total_hits += col->get(); + //} + //sourceLinks->reserve(hits->size()); + //measurements->reserve(hits->size()); debug() << " m_trackerHitCollections size : " << m_trackerHitCollections.size() << endmsg; + int ihit = 0; for(const auto col : m_trackerHitCollections) { // input collection const eic::TrackerHitCollection* hits = col->get(); - //const eic::TrackerHitCollection* hits = get<eic::TrackerHitCollection>("/Event/"+ col); + // const eic::TrackerHitCollection* hits = get<eic::TrackerHitCollection>("/Event/"+ col); debug() << (*hits).size() << " hits " << endmsg; - for(const auto& ahit : *hits) { + for (const auto& ahit : *hits) { + + //allHits->push_back(ahit.clone()); - Acts::BoundMatrix cov = Acts::BoundMatrix::Zero(); - cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = ahit.covsym_xx()*Acts::UnitConstants::mm*ahit.covsym_xx()*Acts::UnitConstants::mm; - cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = ahit.covsym_yy()*Acts::UnitConstants::mm*ahit.covsym_yy()*Acts::UnitConstants::mm; + Acts::SymMatrix2 cov = Acts::SymMatrix2::Zero(); + cov(0, 0) = ahit.covsym_xx() * Acts::UnitConstants::mm * ahit.covsym_xx() * Acts::UnitConstants::mm; + cov(1, 1) = ahit.covsym_yy() * Acts::UnitConstants::mm * ahit.covsym_yy() * Acts::UnitConstants::mm; - auto vol_ctx = m_geoSvc->cellIDPositionConverter()->findContext(ahit.cellID()); - auto vol_id = vol_ctx->identifier; - //debug() << " hit : \n" << ahit << endmsg; - //debug() << "cell ID : " << ahit.cellID() << endmsg; - //debug() << " position : (" << ahit.position(0) << ", " << ahit.position(1) << ", "<< ahit.position(2) << ") " << endmsg; - debug() << " vol_id : " << vol_id << endmsg; - debug() << " placment pos : " << vol_ctx->volumePlacement().position() << endmsg; + auto vol_ctx = m_geoSvc->cellIDPositionConverter()->findContext(ahit.cellID()); + auto vol_id = vol_ctx->identifier; + const auto is = m_surfaces.find(vol_id); - const auto is = m_surfaces.find(vol_id); + debug() << " cell ID : 0x" << std::hex << ahit.cellID() << std::dec << endmsg; + debug() << " vol ID : 0x" << std::hex << vol_id << std::dec << endmsg; if (is == m_surfaces.end()) { - debug() << " vol_id (" << vol_id << ") not found in m_surfaces." <<endmsg; + auto detector = m_geoSvc->detector()->volumeManager().lookupDetector(vol_id); + debug() << " detector 0x" << std::hex << detector.id() <<std::dec << ", " << detector.path() << endmsg; + debug() << " vol_id " << vol_id << " (0x" << std::hex << vol_id <<std::dec<< ") not found in m_surfaces." << endmsg; + debug() << "hit " << ihit << endmsg; continue; } const Acts::Surface* surface = is->second; - - debug() << " surface center : " << surface->center(Acts::GeometryContext()) << endmsg; + //debug() << " surface center : " << surface->center(Acts::GeometryContext()) << endmsg; // transform global position into local coordinates - Acts::Vector2D pos(0, 0); + Acts::Vector2 pos(0, 0); // geometry context contains nothing here - pos = surface->globalToLocal(Acts::GeometryContext(), {ahit.x(), ahit.y(), ahit.z()}, {0, 0, 0}).value();//, pos); - - //// smear truth to create local measurement - Acts::BoundVector loc = Acts::BoundVector::Zero(); - loc[Acts::eBoundLoc0] = pos[0] ;//+ m_cfg.sigmaLoc0 * stdNormal(rng); - loc[Acts::eBoundLoc0] = pos[1] ;//+ m_cfg.sigmaLoc1 * stdNormal(rng); - - debug() << "loc : (" << loc[0] << ", " << loc[1] << ")" << endmsg; - - // create source link at the end of the container - //auto it = source_links->emplace_hint(source_links->end(), *surface, hit, 2, loc, cov); - auto it = source_links->emplace_hint(source_links->end(), *surface, 2, loc, cov); - // ensure hits and links share the same order to prevent ugly surprises - if (std::next(it) != source_links->end()) { - error() << "The hit ordering broke. Run for your life." << endmsg; - return StatusCode::FAILURE; - } - - //std::array<double,3> posarr; pos.GetCoordinates(posarr); - //std::array<double,3> dimarr; dim.GetCoordinates(posarr); - //eic::TrackerHit hit; - //eic::TrackerHit hit((long long)ahit.cellID0(), (long long)ahit.cellID(), (long long)ahit.time(), - // (float)ahit.charge() / 10000.0, (float)0.0, {{pos.x(), pos.y(),pos.z()}},{{dim[0],dim[1],0.0}}); - //rec_hits->push_back(hit); + pos = surface->globalToLocal(Acts::GeometryContext(), {ahit.x(), ahit.y(), ahit.z()}, {0, 0, 0}) + .value(); //, pos); + + Acts::Vector2 loc = Acts::Vector2::Zero(); + loc[Acts::eBoundLoc0] = pos[0]; //+ m_cfg.sigmaLoc0 * stdNormal(rng); + loc[Acts::eBoundLoc1] = pos[1]; //+ m_cfg.sigmaLoc1 * stdNormal(rng); + // debug() << "loc : (" << loc[0] << ", " << loc[1] << ")" << endmsg; + // local position + // auto loc = {ahit.x(), ahit.y(), ahit.z()} - vol_ctx->volumePlacement().position() + //debug() << " hit : \n" << ahit << endmsg; + //debug() << " position : (" << ahit.x() << ", " << ahit.y() << ", "<< ahit.z() << + //") " << endmsg; debug() << " vol_id : " << vol_id << endmsg; debug() << " placment pos : " << + //vol_ctx->volumePlacement().position() << endmsg; + + // the measurement container is unordered and the index under which the + // measurement will be stored is known before adding it. + Index hitIdx = measurements->size(); + IndexSourceLink sourceLink(vol_id, ihit); + auto meas = Acts::makeMeasurement(sourceLink, loc, cov, Acts::eBoundLoc0, Acts::eBoundLoc1); + + // add to output containers. since the input is already geometry-order, + // new elements in geometry containers can just be appended at the end. + sourceLinks->emplace_hint(sourceLinks->end(), std::move(sourceLink)); + measurements->emplace_back(std::move(meas)); + + ihit++; } } return StatusCode::SUCCESS; diff --git a/JugReco/src/components/TrackingHitsSourceLinker.cpp b/JugReco/src/components/TrackingHitsSourceLinker.cpp index e9c8d6b9c45b903245491c90a3f62ab241f0f2fc..ad7b147fc4153a0de1a3f1436ae6f614938f4d3a 100644 --- a/JugReco/src/components/TrackingHitsSourceLinker.cpp +++ b/JugReco/src/components/TrackingHitsSourceLinker.cpp @@ -20,8 +20,8 @@ #include "DD4hep/DD4hepUnits.h" -#include "Acts/Utilities/Units.hpp" -#include "Acts/Utilities/Definitions.hpp" +#include "Acts/Definitions/Units.hpp" +#include "Acts/Definitions/Common.hpp" #include "Acts/Geometry/TrackingGeometry.hpp" #include "Acts/Plugins/DD4hep/DD4hepDetectorElement.hpp" diff --git a/VERSION b/VERSION index 26aaba0e86632e4d537006e45b0ec918d780b3b4..88c5fb891dcf1d1647d2b84bac0630cf9570d213 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.0 +1.4.0