Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:01:53

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/Geometry/GeometryContext.hpp"
0013 #include "Acts/Surfaces/Surface.hpp"
0014 #include "Acts/Utilities/AnyGridView.hpp"
0015 #include "Acts/Utilities/AxisDefinitions.hpp"
0016 #include "Acts/Utilities/Grid.hpp"
0017 #include "Acts/Utilities/IAxis.hpp"
0018 
0019 #include <iostream>
0020 #include <type_traits>
0021 #include <vector>
0022 
0023 namespace Acts {
0024 
0025 using SurfaceVector = std::vector<const Surface*>;
0026 
0027 /// @brief Provides Surface binning in N dimensions
0028 ///
0029 /// Uses @c Grid under the hood to implement the storage and lookup
0030 /// Contains a lookup struct which talks to the @c Grid
0031 /// and performs utility actions. This struct needs to be initialised
0032 /// externally and passed to @c SurfaceArray on construction.
0033 class SurfaceArray {
0034  public:
0035   /// @brief Base interface for all surface lookups.
0036   struct ISurfaceGridLookup {
0037     /// @brief Fill provided surfaces into the contained @c Grid.
0038     /// @param gctx The current geometry context object, e.g. alignment
0039 
0040     /// @param surfaces Input surface pointers
0041     virtual void fill(const GeometryContext& gctx,
0042                       const SurfaceVector& surfaces) = 0;
0043 
0044     /// @brief Attempts to fix sub-optimal binning by filling closest
0045     ///        Surfaces into empty bin
0046     ///
0047     /// @param gctx The current geometry context object, e.g. alignment
0048 
0049     /// @param surfaces The surface pointers to fill
0050     /// @return number of bins that were filled
0051     virtual std::size_t completeBinning(const GeometryContext& gctx,
0052                                         const SurfaceVector& surfaces) = 0;
0053 
0054     /// @brief Performs lookup at @c pos and returns bin content as reference
0055     /// @param position Lookup position
0056     /// @return @c SurfaceVector at given bin
0057     virtual SurfaceVector& lookup(const Vector3& position) = 0;
0058 
0059     /// @brief Performs lookup at @c pos and returns bin content as const
0060     /// reference
0061     /// @param position Lookup position
0062     /// @return @c SurfaceVector at given bin
0063     virtual const SurfaceVector& lookup(const Vector3& position) const = 0;
0064 
0065     /// @brief Performs lookup at global bin and returns bin content as
0066     /// reference
0067     /// @param bin Global lookup bin
0068     /// @return @c SurfaceVector at given bin
0069     virtual SurfaceVector& lookup(std::size_t bin) = 0;
0070 
0071     /// @brief Performs lookup at global bin and returns bin content as const
0072     /// reference
0073     /// @param bin Global lookup bin
0074     /// @return @c SurfaceVector at given bin
0075     virtual const SurfaceVector& lookup(std::size_t bin) const = 0;
0076 
0077     /// @brief Performs a lookup at @c pos, but returns neighbors as well
0078     ///
0079     /// @param position Lookup position
0080     /// @return @c SurfaceVector at given bin. Copy of all bins selected
0081     virtual const SurfaceVector& neighbors(const Vector3& position) const = 0;
0082 
0083     /// @brief Returns the total size of the grid (including under/overflow
0084     /// bins)
0085     /// @return Size of the grid data structure
0086     virtual std::size_t size() const = 0;
0087 
0088     /// @brief Gets the center position of bin @c bin in global coordinates
0089     /// @param bin the global bin index
0090     /// @return The bin center
0091     virtual Vector3 getBinCenter(std::size_t bin) const = 0;
0092 
0093     /// @brief Returns copies of the axes used in the grid as @c AnyAxis
0094     /// @return The axes
0095     /// @note This returns copies. Use for introspection and querying.
0096     virtual std::vector<const IAxis*> getAxes() const = 0;
0097 
0098     virtual std::optional<AnyGridConstView<SurfaceVector>> getGridView()
0099         const = 0;
0100 
0101     virtual const Transform3& getTransform() const = 0;
0102 
0103     virtual Surface::SurfaceType surfaceType() const = 0;
0104 
0105     /// @brief Get the number of dimensions of the grid.
0106     /// @return number of dimensions
0107     virtual std::size_t dimensions() const = 0;
0108 
0109     /// @brief Checks if global bin is valid
0110     /// @param bin the global bin index
0111     /// @return bool if the bin is valid
0112     /// @note Valid means that the index points to a bin which is not a under
0113     ///       or overflow bin or out of range in any axis.
0114     virtual bool isValidBin(std::size_t bin) const = 0;
0115 
0116     /// @brief The binning values described by this surface grid lookup
0117     /// They are in order of the axes (optional) and empty for eingle lookups
0118     virtual std::vector<AxisDirection> binningValues() const { return {}; };
0119 
0120     /// Pure virtual destructor
0121     virtual ~ISurfaceGridLookup() = 0;
0122   };
0123 
0124   /// @brief Lookup helper which encapsulates a @c Grid
0125   /// @tparam Axes The axes used for the grid
0126   template <class... Axes>
0127   struct SurfaceGridLookup : ISurfaceGridLookup {
0128     static constexpr std::size_t DIM = sizeof...(Axes);
0129 
0130    public:
0131     /// @brief Specifies the local coordinate type.
0132     /// This resolves to @c ActsVector<DIM> for DIM > 1, else @c
0133     /// std::array<double, 1>
0134     using point_t =
0135         std::conditional_t<DIM == 1, std::array<double, 1>, ActsVector<DIM>>;
0136     using Grid_t = Grid<SurfaceVector, Axes...>;
0137 
0138     /// @brief Default constructor
0139     ///
0140     /// @param type The surface type, this determines the local to global calculation
0141     /// @param transform The transform to apply to the surface`
0142     /// @param R the radius (interpretation depends on @p type)
0143     /// @param Z the z position (interpretation depends on @p type)
0144     /// @param axes The axes to build the grid data structure.
0145     /// @param bValues What the axes represent (optional)
0146     /// @note Signature of localToGlobal and globalToLocal depends on @c DIM.
0147     ///       If DIM > 1, local coords are @c ActsVector<DIM> else
0148     ///       @c std::array<double, 1>.
0149     SurfaceGridLookup(Surface::SurfaceType type, const Transform3& transform,
0150                       double R, double Z, std::tuple<Axes...> axes,
0151                       std::vector<AxisDirection> bValues = {})
0152         : m_type(type),
0153           m_transform(transform),
0154           m_itransform(transform.inverse()),
0155           m_grid(std::move(axes)),
0156           m_binValues(std::move(bValues)) {
0157       m_neighborMap.resize(m_grid.size());
0158 
0159       using namespace VectorHelpers;
0160 
0161       switch (type) {
0162         using enum Surface::SurfaceType;
0163         case Cylinder:
0164           m_globalToLocal = [](const Vector3& pos) {
0165             return Vector2(phi(pos), pos.z());
0166           };
0167           m_localToGlobal = [R](const Vector2& loc) {
0168             // Technically, this is not correct, the radius is arbitrary
0169             return Vector3(R * std::cos(loc[0]), R * std::sin(loc[0]), loc[1]);
0170           };
0171           break;
0172         case Disc:
0173           m_globalToLocal = [](const Vector3& pos) {
0174             return Vector2(perp(pos), phi(pos));
0175           };
0176           m_localToGlobal = [Z](const Vector2& loc) {
0177             // Technically, this is not correct, the z position is arbitrary
0178             return Vector3(loc[0] * std::cos(loc[1]), loc[0] * std::sin(loc[1]),
0179                            Z);
0180           };
0181           break;
0182         case Plane:
0183           m_globalToLocal = [](const Vector3& pos) {
0184             return Vector2(perp(pos), phi(pos));
0185           };
0186           m_localToGlobal = [](const Vector2& loc) {
0187             return Vector3(loc.x(), loc.y(), 0.);
0188           };
0189           break;
0190         default:
0191           throw std::invalid_argument("Surface type not supported");
0192       }
0193     }
0194 
0195     /// @brief Fill provided surfaces into the contained @c Grid.
0196     ///
0197     /// This is done by iterating, accessing the referencePosition, lookup
0198     /// and append.
0199     /// Also populates the neighbor map by combining the filled bins of
0200     /// all bins around a given one.
0201     ///
0202     /// @param gctx The current geometry context object, e.g. alignment
0203     /// @param surfaces Input surface pointers
0204     void fill(const GeometryContext& gctx,
0205               const SurfaceVector& surfaces) override {
0206       for (const auto& srf : surfaces) {
0207         Vector3 pos = srf->referencePosition(gctx, AxisDirection::AxisR);
0208         lookup(pos).push_back(srf);
0209       }
0210 
0211       populateNeighborCache();
0212     }
0213 
0214     /// @brief Attempts to fix sub-optimal binning by filling closest
0215     ///        Surfaces into empty bins
0216     /// @note This does not always do what you want.
0217     ///
0218     /// @param gctx The current geometry context object, e.g. alignment
0219     /// @param surfaces The surface pointers to fill
0220     /// @return number of bins that were filled
0221     std::size_t completeBinning(const GeometryContext& gctx,
0222                                 const SurfaceVector& surfaces) override {
0223       std::size_t binCompleted = 0;
0224       std::size_t nBins = size();
0225       double minPath = 0;
0226       double curPath = 0;
0227       const Surface* minSrf = nullptr;
0228 
0229       for (std::size_t b = 0; b < nBins; ++b) {
0230         if (!isValidBin(b)) {
0231           continue;
0232         }
0233         std::vector<const Surface*>& binContent = lookup(b);
0234         // only complete if we have an empty bin
0235         if (!binContent.empty()) {
0236           continue;
0237         }
0238 
0239         Vector3 binCtr = getBinCenter(b);
0240         minPath = std::numeric_limits<double>::max();
0241         for (const auto& srf : surfaces) {
0242           curPath =
0243               (binCtr - srf->referencePosition(gctx, AxisDirection::AxisR))
0244                   .norm();
0245 
0246           if (curPath < minPath) {
0247             minPath = curPath;
0248             minSrf = srf;
0249           }
0250         }
0251 
0252         binContent.push_back(minSrf);
0253         ++binCompleted;
0254       }
0255 
0256       // recreate neighborcache
0257       populateNeighborCache();
0258       return binCompleted;
0259     }
0260 
0261     /// @brief Performs lookup at @c pos and returns bin content as reference
0262     /// @param position Lookup position
0263     /// @return @c SurfaceVector at given bin
0264     SurfaceVector& lookup(const Vector3& position) override {
0265       return m_grid.atPosition(m_globalToLocal(m_transform * position));
0266     }
0267 
0268     /// @brief Performs lookup at @c pos and returns bin content as const
0269     /// reference
0270     /// @param position Lookup position
0271     /// @return @c SurfaceVector at given bin
0272     const SurfaceVector& lookup(const Vector3& position) const override {
0273       return m_grid.atPosition(m_globalToLocal(m_transform * position));
0274     }
0275 
0276     /// @brief Performs lookup at global bin and returns bin content as
0277     /// reference
0278     /// @param bin Global lookup bin
0279     /// @return @c SurfaceVector at given bin
0280     SurfaceVector& lookup(std::size_t bin) override { return m_grid.at(bin); }
0281 
0282     /// @brief Performs lookup at global bin and returns bin content as const
0283     /// reference
0284     /// @param bin Global lookup bin
0285     /// @return @c SurfaceVector at given bin
0286     const SurfaceVector& lookup(std::size_t bin) const override {
0287       return m_grid.at(bin);
0288     }
0289 
0290     /// @brief Performs a lookup at @c pos, but returns neighbors as well
0291     ///
0292     /// @param position Lookup position
0293     /// @return @c SurfaceVector at given bin. Copy of all bins selected
0294     const SurfaceVector& neighbors(const Vector3& position) const override {
0295       auto lposition = m_globalToLocal(m_transform * position);
0296       return m_neighborMap.at(m_grid.globalBinFromPosition(lposition));
0297     }
0298 
0299     /// @brief Returns the total size of the grid (including under/overflow
0300     /// bins)
0301     /// @return Size of the grid data structure
0302     std::size_t size() const override { return m_grid.size(); }
0303 
0304     /// @brief The binning values described by this surface grid lookup
0305     /// They are in order of the axes
0306     std::vector<AxisDirection> binningValues() const override {
0307       return m_binValues;
0308     }
0309 
0310     /// @brief Gets the center position of bin @c bin in global coordinates
0311     /// @param bin the global bin index
0312     /// @return The bin center
0313     Vector3 getBinCenter(std::size_t bin) const override {
0314       return getBinCenterImpl(bin);
0315     }
0316 
0317     /// @brief Returns copies of the axes used in the grid as @c AnyAxis
0318     /// @return The axes
0319     /// @note This returns copies. Use for introspection and querying.
0320     std::vector<const IAxis*> getAxes() const override {
0321       auto arr = m_grid.axes();
0322       return std::vector<const IAxis*>(arr.begin(), arr.end());
0323     }
0324 
0325     std::optional<AnyGridConstView<SurfaceVector>> getGridView()
0326         const override {
0327       return AnyGridConstView<SurfaceVector>{m_grid};
0328     }
0329 
0330     const Transform3& getTransform() const override { return m_transform; }
0331 
0332     Surface::SurfaceType surfaceType() const override { return m_type; }
0333 
0334     /// @brief Get the number of dimensions of the grid.
0335     /// @return number of dimensions
0336     std::size_t dimensions() const override { return DIM; }
0337 
0338     /// @brief Checks if global bin is valid
0339     /// @param bin the global bin index
0340     /// @return bool if the bin is valid
0341     /// @note Valid means that the index points to a bin which is not a under
0342     ///       or overflow bin or out of range in any axis.
0343     bool isValidBin(std::size_t bin) const override {
0344       std::array<std::size_t, DIM> indices = m_grid.localBinsFromGlobalBin(bin);
0345       std::array<std::size_t, DIM> nBins = m_grid.numLocalBins();
0346       for (std::size_t i = 0; i < indices.size(); ++i) {
0347         std::size_t idx = indices.at(i);
0348         if (idx <= 0 || idx >= nBins.at(i) + 1) {
0349           return false;
0350         }
0351       }
0352 
0353       return true;
0354     }
0355 
0356    private:
0357     void populateNeighborCache() {
0358       // calculate neighbors for every bin and store in map
0359       for (std::size_t i = 0; i < m_grid.size(); i++) {
0360         if (!isValidBin(i)) {
0361           continue;
0362         }
0363         typename Grid_t::index_t loc = m_grid.localBinsFromGlobalBin(i);
0364         auto neighborIdxs = m_grid.neighborHoodIndices(loc, 1u);
0365         std::vector<const Surface*>& neighbors = m_neighborMap.at(i);
0366         neighbors.clear();
0367 
0368         for (const auto idx : neighborIdxs) {
0369           const std::vector<const Surface*>& binContent = m_grid.at(idx);
0370           std::copy(binContent.begin(), binContent.end(),
0371                     std::back_inserter(neighbors));
0372         }
0373       }
0374     }
0375 
0376     /// Internal method.
0377     /// This is here, because apparently Eigen doesn't like Vector1.
0378     /// So SurfaceGridLookup internally uses std::array<double, 1> instead
0379     /// of Vector1 (see the point_t typedef). This needs to be switched here,
0380     /// so as not to
0381     /// attempt an initialization of Vector1 that Eigen will complain about.
0382     /// The SFINAE is hidden in this private method so the public
0383     /// interface stays the same, since we don't care what happens
0384     /// here on the callers end
0385     /// This is the version for DIM>1
0386     Vector3 getBinCenterImpl(std::size_t bin) const
0387       requires(DIM != 1)
0388     {
0389       return m_itransform *
0390              m_localToGlobal(ActsVector<DIM>(
0391                  m_grid.binCenter(m_grid.localBinsFromGlobalBin(bin)).data()));
0392     }
0393 
0394     /// Internal method, see above.
0395     /// This is the version for DIM==1
0396     Vector3 getBinCenterImpl(std::size_t bin) const
0397       requires(DIM == 1)
0398     {
0399       point_t pos = m_grid.binCenter(m_grid.localBinsFromGlobalBin(bin));
0400       return m_itransform * m_localToGlobal(pos);
0401     }
0402 
0403     Surface::SurfaceType m_type;
0404     Transform3 m_transform;
0405     Transform3 m_itransform;
0406     std::function<point_t(const Vector3&)> m_globalToLocal;
0407     std::function<Vector3(const point_t&)> m_localToGlobal;
0408     Grid_t m_grid;
0409     std::vector<AxisDirection> m_binValues;
0410     std::vector<SurfaceVector> m_neighborMap;
0411   };
0412 
0413   /// @brief Lookup implementation which wraps one element and always returns
0414   ///        this element when lookup is called
0415   struct SingleElementLookup : ISurfaceGridLookup {
0416     /// @brief Default constructor.
0417     /// @param element the one and only element.
0418     explicit SingleElementLookup(SurfaceVector::value_type element)
0419         : m_element({element}) {}
0420 
0421     /// @brief Default constructor.
0422     /// @param elements the surfaces that are provided through a single lookup
0423     explicit SingleElementLookup(const SurfaceVector& elements)
0424         : m_element(elements) {}
0425 
0426     /// @brief Lookup, always returns @c element
0427     /// @return reference to vector containing only @c element
0428     SurfaceVector& lookup(const Vector3& /*position*/) override {
0429       return m_element;
0430     }
0431 
0432     /// @brief Lookup, always returns @c element
0433     /// @return reference to vector containing only @c element
0434     const SurfaceVector& lookup(const Vector3& /*position*/) const override {
0435       return m_element;
0436     }
0437 
0438     /// @brief Lookup, always returns @c element
0439     /// @return reference to vector containing only @c element
0440     SurfaceVector& lookup(std::size_t /*bin*/) override { return m_element; }
0441 
0442     /// @brief Lookup, always returns @c element
0443     /// @return reference to vector containing only @c element
0444     const SurfaceVector& lookup(std::size_t /*bin*/) const override {
0445       return m_element;
0446     }
0447 
0448     /// @brief Lookup, always returns @c element
0449     /// @return reference to vector containing only @c element
0450     const SurfaceVector& neighbors(const Vector3& /*position*/) const override {
0451       return m_element;
0452     }
0453 
0454     /// @brief returns 1
0455     /// @return 1
0456     std::size_t size() const override { return 1; }
0457 
0458     /// @brief Gets the bin center, but always returns (0, 0, 0)
0459     /// @return (0, 0, 0)
0460     Vector3 getBinCenter(std::size_t /*bin*/) const override {
0461       return Vector3(0, 0, 0);
0462     }
0463 
0464     /// @brief Returns an empty vector of @c AnyAxis
0465     /// @return empty vector
0466     std::vector<const IAxis*> getAxes() const override { return {}; }
0467 
0468     std::optional<AnyGridConstView<SurfaceVector>> getGridView()
0469         const override {
0470       return std::nullopt;
0471     }
0472 
0473     const Transform3& getTransform() const override {
0474       static const Transform3 identityTransform = Transform3::Identity();
0475       return identityTransform;
0476     }
0477 
0478     Surface::SurfaceType surfaceType() const override {
0479       return Surface::SurfaceType::Other;
0480     }
0481 
0482     /// @brief Get the number of dimensions
0483     /// @return always 0
0484     std::size_t dimensions() const override { return 0; }
0485 
0486     /// @brief Comply with concept and provide fill method
0487     /// @note Does nothing
0488     void fill(const GeometryContext& /*gctx*/,
0489               const SurfaceVector& /*surfaces*/) override {}
0490 
0491     /// @brief Comply with concept and provide completeBinning method
0492     /// @note Does nothing
0493     std::size_t completeBinning(const GeometryContext& /*gctx*/,
0494                                 const SurfaceVector& /*surfaces*/) override {
0495       return 0;
0496     }
0497 
0498     /// @brief Returns if the bin is valid (it is)
0499     /// @return always true
0500     bool isValidBin(std::size_t /*bin*/) const override { return true; }
0501 
0502    private:
0503     SurfaceVector m_element;
0504   };
0505 
0506   /// @brief Default constructor which takes a @c SurfaceLookup and a vector of
0507   /// surfaces
0508   /// @param gridLookup The grid storage. @c SurfaceArray does not fill it on
0509   /// its own
0510   /// @param surfaces The input vector of surfaces. This is only for
0511   /// bookkeeping, so we can ask
0512   /// @param transform Optional additional transform for this SurfaceArray
0513   explicit SurfaceArray(std::unique_ptr<ISurfaceGridLookup> gridLookup,
0514                         std::vector<std::shared_ptr<const Surface>> surfaces,
0515                         const Transform3& transform = Transform3::Identity());
0516 
0517   /// @brief Constructor with a single surface
0518   /// @param srf The one and only surface
0519   explicit SurfaceArray(std::shared_ptr<const Surface> srf);
0520 
0521   /// @brief Get all surfaces in bin given by position.
0522   /// @param position the lookup position
0523   /// @return reference to @c SurfaceVector contained in bin at that position
0524   SurfaceVector& at(const Vector3& position) {
0525     return p_gridLookup->lookup(position);
0526   }
0527 
0528   /// @brief Get all surfaces in bin given by position @p pos.
0529   /// @param position the lookup position
0530   /// @return const reference to @c SurfaceVector contained in bin at that
0531   /// position
0532   const SurfaceVector& at(const Vector3& position) const {
0533     return p_gridLookup->lookup(position);
0534   }
0535 
0536   /// @brief Get all surfaces in bin given by global bin index @p bin.
0537   /// @param bin the global bin index
0538   /// @return reference to @c SurfaceVector contained in bin
0539   SurfaceVector& at(std::size_t bin) { return p_gridLookup->lookup(bin); }
0540 
0541   /// @brief Get all surfaces in bin given by global bin index.
0542   /// @param bin the global bin index
0543   /// @return const reference to @c SurfaceVector contained in bin
0544   const SurfaceVector& at(std::size_t bin) const {
0545     return p_gridLookup->lookup(bin);
0546   }
0547 
0548   /// @brief Get all surfaces in bin at @p pos and its neighbors
0549   /// @param position The position to lookup as nominal
0550   /// @return Merged @c SurfaceVector of neighbors and nominal
0551   /// @note The @c SurfaceVector will be combined. For technical reasons, the
0552   ///       different bin content vectors have to be copied, so the resulting
0553   ///       vector contains copies.
0554   const SurfaceVector& neighbors(const Vector3& position) const {
0555     return p_gridLookup->neighbors(position);
0556   }
0557 
0558   /// @brief Get the size of the underlying grid structure including
0559   /// under/overflow bins
0560   /// @return the size
0561   std::size_t size() const { return p_gridLookup->size(); }
0562 
0563   /// @brief Get the center of the bin identified by global bin index @p bin
0564   /// @param bin the global bin index
0565   /// @return Center position of the bin in global coordinates
0566   Vector3 getBinCenter(std::size_t bin) const {
0567     return p_gridLookup->getBinCenter(bin);
0568   }
0569 
0570   /// @brief Get all surfaces attached to this @c SurfaceArray
0571   /// @return Reference to @c SurfaceVector containing all surfaces
0572   /// @note This does not reflect the actual state of the grid. It only
0573   ///       returns what was given in the constructor, without any checks
0574   ///       if that is actually what's in the grid.
0575   const SurfaceVector& surfaces() const { return m_surfacesRawPointers; }
0576 
0577   /// @brief Get vector of axes spanning the grid as @c AnyAxis
0578   /// @return vector of @c AnyAxis
0579   /// @note The axes in the vector are copies. Only use for introspection and
0580   ///       querying.
0581   std::vector<const IAxis*> getAxes() const { return p_gridLookup->getAxes(); }
0582 
0583   /// @brief Checks if global bin is valid
0584   /// @param bin the global bin index
0585   /// @return bool if the bin is valid
0586   /// @note Valid means that the index points to a bin which is not a under
0587   ///       or overflow bin or out of range in any axis.
0588   bool isValidBin(std::size_t bin) const {
0589     return p_gridLookup->isValidBin(bin);
0590   }
0591 
0592   const Transform3& transform() const { return m_transform; }
0593 
0594   /// @brief The binning values described by this surface grid lookup
0595   /// They are in order of the axes
0596   std::vector<AxisDirection> binningValues() const {
0597     return p_gridLookup->binningValues();
0598   };
0599 
0600   /// @brief String representation of this @c SurfaceArray
0601   /// @param gctx The current geometry context object, e.g. alignment
0602   /// @param sl Output stream to write to
0603   /// @return the output stream given as @p sl
0604   std::ostream& toStream(const GeometryContext& gctx, std::ostream& sl) const;
0605 
0606   /// Return the lookup object
0607   const ISurfaceGridLookup& gridLookup() const { return *p_gridLookup; }
0608 
0609  private:
0610   std::unique_ptr<ISurfaceGridLookup> p_gridLookup;
0611   // this vector makes sure we have shared ownership over the surfaces
0612   std::vector<std::shared_ptr<const Surface>> m_surfaces;
0613   // this vector is returned, so that (expensive) copying of the shared_ptr
0614   // vector does not happen by default
0615   SurfaceVector m_surfacesRawPointers;
0616   // this is only used to keep info on transform applied
0617   // by l2g and g2l
0618   Transform3 m_transform;
0619 };
0620 
0621 }  // namespace Acts