Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-08 08:20:13

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #pragma once
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Material/IVolumeMaterial.hpp"
0013 #include "Acts/Material/Material.hpp"
0014 #include "Acts/Utilities/BinUtility.hpp"
0015 #include "Acts/Utilities/Interpolation.hpp"
0016 
0017 #include <functional>
0018 #include <optional>
0019 
0020 namespace Acts {
0021 
0022 /// @addtogroup material
0023 /// @{
0024 
0025 /// @brief Struct for mapping global 3D positions to material values
0026 ///
0027 /// Global 3D positions are transformed into a @c DIM_POS Dimensional vector
0028 /// which is used to look up the material classification value in the
0029 /// underlying material map.
0030 template <typename G>
0031 struct MaterialMapLookup {
0032  public:
0033   /// Type alias for material grid
0034   using Grid_t = G;
0035   /// Dimensionality of the position space for material interpolation
0036   static constexpr std::size_t DIM_POS = Grid_t::DIM;
0037 
0038   /// @brief Struct representing smallest grid unit in material grid
0039   ///
0040   /// This type encapsulate all required information to perform linear
0041   /// interpolation of material classification values within a 3D volume.
0042   struct MaterialCell {
0043     /// Number of corner points defining the confining hyper-box
0044     static constexpr unsigned int N = 1 << DIM_POS;
0045 
0046     /// @brief Default constructor
0047     ///
0048     /// @param [in] transformPos   Mapping of global 3D coordinates onto grid
0049     /// space
0050     /// @param [in] lowerLeft   Generalized lower-left corner of hyper box
0051     ///                         (containing the minima of the hyper box along
0052     ///                         each Dimension)
0053     /// @param [in] upperRight  Generalized upper-right corner of hyper box
0054     ///                         (containing the maxima of the hyper box along
0055     ///                         each Dimension)
0056     /// @param [in] materialValues Material classification values at the hyper
0057     /// box corners sorted in the canonical order defined in Acts::interpolate
0058     MaterialCell(std::function<Vector<DIM_POS>(const Vector3&)> transformPos,
0059                  std::array<double, DIM_POS> lowerLeft,
0060                  std::array<double, DIM_POS> upperRight,
0061                  std::array<Material::ParametersVector, N> materialValues)
0062         : m_transformPos(std::move(transformPos)),
0063           m_lowerLeft(std::move(lowerLeft)),
0064           m_upperRight(std::move(upperRight)),
0065           m_materialValues(std::move(materialValues)) {}
0066 
0067     /// @brief Retrieve material at given position
0068     ///
0069     /// @param [in] position Global 3D position
0070     /// @return Material at the given position
0071     ///
0072     /// @pre The given @c position must lie within the current cell.
0073     Material getMaterial(const Vector3& position) const {
0074       // defined in Interpolation.hpp
0075       return Material(interpolate(m_transformPos(position), m_lowerLeft,
0076                                   m_upperRight, m_materialValues));
0077     }
0078 
0079     /// @brief Check whether given 3D position is inside this cell
0080     ///
0081     /// @param [in] position Global 3D position
0082     /// @return @c true if position is inside the current cell,
0083     ///         otherwise @c false
0084     bool isInside(const Vector3& position) const {
0085       const auto& gridCoordinates = m_transformPos(position);
0086       for (unsigned int i = 0; i < DIM_POS; ++i) {
0087         if (gridCoordinates[i] < m_lowerLeft.at(i) ||
0088             gridCoordinates[i] >= m_upperRight.at(i)) {
0089           return false;
0090         }
0091       }
0092       return true;
0093     }
0094 
0095    private:
0096     /// Geometric transformation applied to global 3D positions
0097     std::function<Vector<DIM_POS>(const Vector3&)> m_transformPos;
0098 
0099     /// Generalized lower-left corner of the confining hyper-box
0100     std::array<double, DIM_POS> m_lowerLeft;
0101 
0102     /// Generalized upper-right corner of the confining hyper-box
0103     std::array<double, DIM_POS> m_upperRight;
0104 
0105     /// @brief Material component vectors at the hyper-box corners
0106     ///
0107     /// @note These values must be order according to the prescription detailed
0108     ///       in Acts::interpolate.
0109     std::array<Material::ParametersVector, N> m_materialValues;
0110   };
0111 
0112   /// @brief Default constructor
0113   ///
0114   /// @param [in] transformPos Mapping of global 3D coordinates (cartesian)
0115   /// onto grid space
0116   /// @param [in] grid Grid storing material classification values
0117   MaterialMapLookup(std::function<Vector<DIM_POS>(const Vector3&)> transformPos,
0118                     Grid_t grid)
0119       : m_transformPos(std::move(transformPos)), m_grid(std::move(grid)) {}
0120 
0121   /// @brief Retrieve binned material at given position
0122   ///
0123   /// @param [in] position Global 3D position
0124   /// @return Material at the given position
0125   ///
0126   /// @pre The given @c position must lie within the range of the underlying
0127   /// map.
0128   Material material(const Vector3& position) const {
0129     return Material(
0130         m_grid.atLocalBins(m_grid.multiAxis().getLocalBinsFromLowerLeftEdge(
0131             m_transformPos(position))));
0132   }
0133 
0134   /// @brief Retrieve interpolated material at given position
0135   ///
0136   /// @param [in] position Global 3D position
0137   /// @return Material at the given position
0138   ///
0139   /// @pre The given @c position must lie within the range of the underlying
0140   /// map.
0141   Material getMaterial(const Vector3& position) const {
0142     return Material(m_grid.interpolate(m_transformPos(position)));
0143   }
0144 
0145   /// @brief Retrieve material cell for given position
0146   ///
0147   /// @param [in] position Global 3D position
0148   /// @return material cell containing the given global position
0149   ///
0150   /// @pre The given @c position must lie within the range of the underlying
0151   /// map.
0152   MaterialCell getMaterialCell(const Vector3& position) const {
0153     const auto& gridPosition = m_transformPos(position);
0154     std::size_t bin = m_grid.multiAxis().getGlobalBinFromPoint(gridPosition);
0155     const auto& indices = m_grid.multiAxis().getLocalBinsFromGlobalBin(bin);
0156     const auto& lowerLeft = m_grid.multiAxis().getLowerLeftBinEdge(indices);
0157     const auto& upperRight = m_grid.multiAxis().getUpperRightBinEdge(indices);
0158 
0159     // Loop through all corner points
0160     constexpr std::size_t nCorners = 1 << DIM_POS;
0161     std::array<Material::ParametersVector, nCorners> neighbors{};
0162     const auto& cornerIndices =
0163         m_grid.multiAxis().getClosestPointsIndices(gridPosition);
0164 
0165     std::size_t i = 0;
0166     for (std::size_t index : cornerIndices) {
0167       neighbors.at(i++) = m_grid.at(index);
0168     }
0169 
0170     return MaterialCell(m_transformPos, lowerLeft, upperRight,
0171                         std::move(neighbors));
0172   }
0173 
0174   /// @brief Get the number of bins for all axes of the map
0175   ///
0176   /// @return Vector returning number of bins for all map axes
0177   std::vector<std::size_t> getNBins() const {
0178     auto nBinsArray = m_grid.multiAxis().getNBins();
0179     return std::vector<std::size_t>(nBinsArray.begin(), nBinsArray.end());
0180   }
0181 
0182   /// @brief Get the minimum value of all axes of the map
0183   ///
0184   /// @return Vector returning the minima of all map axes
0185   std::vector<double> getMin() const {
0186     auto minArray = m_grid.multiAxis().getMinPoint();
0187     return std::vector<double>(minArray.begin(), minArray.end());
0188   }
0189 
0190   /// @brief Get the maximum value of all axes of the map
0191   ///
0192   /// @return Vector returning the maxima of all map axes
0193   std::vector<double> getMax() const {
0194     auto maxArray = m_grid.multiAxis().getMaxPoint();
0195     return std::vector<double>(maxArray.begin(), maxArray.end());
0196   }
0197 
0198   /// @brief Check whether given 3D position is inside look-up domain
0199   ///
0200   /// @param [in] position Global 3D position
0201   /// @return @c true if position is inside the defined look-up grid,
0202   ///         otherwise @c false
0203   bool isInside(const Vector3& position) const {
0204     return m_grid.multiAxis().isInside(m_transformPos(position));
0205   }
0206 
0207   /// @brief Get a const reference on the underlying grid structure
0208   ///
0209   /// @return Grid reference
0210   const Grid_t& getGrid() const { return m_grid; }
0211 
0212  private:
0213   /// Geometric transformation applied to global 3D positions
0214   std::function<Vector<DIM_POS>(const Vector3&)> m_transformPos;
0215   /// Grid storing material values
0216   Grid_t m_grid;
0217 };
0218 
0219 /// @brief Interpolate material classification values from material values on a
0220 /// given grid
0221 ///
0222 /// This class implements a material service which is initialized by a
0223 /// material map defined by:
0224 /// - a list of material values on a regular grid in some n-Dimensional space,
0225 /// - a transformation of global 3D coordinates onto this n-Dimensional
0226 /// space.
0227 /// - a transformation of local n-Dimensional material coordinates into
0228 /// global (cartesian) 3D coordinates
0229 ///
0230 /// The material value for a given global position is then determined by:
0231 /// - mapping the position onto the grid,
0232 /// - looking up the material classification values on the closest grid points,
0233 /// - doing a linear interpolation of these values.
0234 /// @warning Each classification number of the material is interpolated
0235 /// independently and thus does not consider any correlations that exists
0236 /// between these values. This might work out since the used material is already
0237 /// a mean of the materials in a certain bin and can therewith be treated as a
0238 /// collection of numbers.
0239 /// @tparam G Type of the grid
0240 template <typename Mapper_t>
0241 class InterpolatedMaterialMap : public IVolumeMaterial {
0242  public:
0243   /// @brief Temporary storage of a certain cell to improve material access
0244   struct Cache {
0245     /// Stored material cell
0246     std::optional<typename Mapper_t::MaterialCell> matCell;
0247     /// Boolean statement if the cell is initialized
0248     bool initialized = false;
0249   };
0250 
0251   /// @brief Create interpolated map
0252   ///
0253   /// @param [in] mapper Material map
0254   explicit InterpolatedMaterialMap(Mapper_t&& mapper)
0255       : m_mapper(std::move(mapper)) {}
0256 
0257   /// @brief Create interpolated map
0258   ///
0259   /// @param [in] mapper Material map
0260   /// @param [in] bu @c BinUtility for build from
0261   InterpolatedMaterialMap(Mapper_t&& mapper, BinUtility bu)
0262       : m_mapper(std::move(mapper)), m_binUtility(std::move(bu)) {}
0263 
0264   /// @brief Retrieve the binned material
0265   ///
0266   /// @param [in] position Global 3D position
0267   ///
0268   /// @return Material at given position
0269   const Material material(const Vector3& position) const override {
0270     return m_mapper.material(position);
0271   }
0272 
0273   /// @brief Retrieve the interpolated material
0274   ///
0275   /// @param [in] position Global 3D position
0276   ///
0277   /// @return material at given position
0278   Material getMaterial(const Vector3& position) const {
0279     return m_mapper.getMaterial(position);
0280   }
0281 
0282   /// @brief Retrieve material
0283   ///
0284   /// @param [in] position Global 3D position
0285   /// @param [in,out] cache Cache object. Contains material cell used for
0286   /// interpolation
0287   ///
0288   /// @return material at given position
0289   Material getMaterial(const Vector3& position, Cache& cache) const {
0290     if (!cache.initialized || !(*cache.matCell).isInside(position)) {
0291       cache.matCell = getMaterialCell(position);
0292       cache.initialized = true;
0293     }
0294     return (*cache.matCell).getMaterial(position);
0295   }
0296 
0297   /// @brief Retrieve material value & its "gradient"
0298   ///
0299   /// @param [in]  position   Global 3D position
0300   /// @return Material
0301   ///
0302   /// @note Currently the derivative is not calculated
0303   /// @todo return derivative
0304   Material getMaterialGradient(const Vector3& position,
0305                                Matrix<5, 5>& /*derivative*/) const {
0306     return m_mapper.getMaterial(position);
0307   }
0308 
0309   /// @brief Retrieve material value & its "gradient"
0310   ///
0311   /// @param [in]  position   Global 3D position
0312   /// @return Material
0313   ///
0314   /// @note Currently the derivative is not calculated
0315   /// @note Cache is not used currently
0316   /// @todo return derivative
0317   Material getMaterialGradient(const Vector3& position,
0318                                Matrix<5, 5>& /*derivative*/,
0319                                Cache& /*cache*/) const {
0320     return m_mapper.getMaterial(position);
0321   }
0322 
0323   /// @brief Convenience method to access underlying material mapper
0324   ///
0325   /// @return The material mapper
0326   const Mapper_t& getMapper() const { return m_mapper; }
0327 
0328   /// @brief Check whether given 3D position is inside look-up domain
0329   ///
0330   /// @param [in] position Global 3D position
0331   /// @return @c true if position is inside the defined map, otherwise @c false
0332   bool isInside(const Vector3& position) const {
0333     return m_mapper.isInside(position);
0334   }
0335 
0336   /// Return the BinUtility
0337   /// @return Const reference to the bin utility for the material map
0338   const BinUtility& binUtility() const { return m_binUtility; }
0339 
0340   /// Output Method for std::ostream
0341   ///
0342   /// @param sl The outoput stream
0343   /// @return Reference to the output stream for method chaining
0344   std::ostream& toStream(std::ostream& sl) const override {
0345     sl << "Acts::InterpolatedMaterialMap : " << std::endl;
0346     sl << "   - Number of Material bins [0,1] : " << m_binUtility.max(0) + 1
0347        << " / " << m_binUtility.max(1) + 1 << std::endl;
0348     sl << "   - Parse full update material    : " << std::endl;
0349     return sl;
0350   }
0351 
0352  private:
0353   /// @brief Retrieve cell for given position
0354   ///
0355   /// @param [in] position Global 3D position
0356   /// @return Material cell containing the given global position
0357   ///
0358   /// @pre The given @c position must lie within the range of the underlying
0359   /// map.
0360   typename Mapper_t::MaterialCell getMaterialCell(
0361       const Vector3& position) const {
0362     return m_mapper.getMaterialCell(position);
0363   }
0364 
0365   /// @brief object for global coordinate transformation and interpolation
0366   ///
0367   /// This object performs the mapping of the global 3D coordinates onto the
0368   /// material grid and the interpolation of the material component values on
0369   /// close-by grid points.
0370   Mapper_t m_mapper;
0371 
0372   BinUtility m_binUtility{};
0373 };
0374 
0375 /// @}
0376 }  // namespace Acts