Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-02 08:17:14

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/Definitions/Direction.hpp"
0013 #include "Acts/Utilities/AxisDefinitions.hpp"
0014 #include "Acts/Utilities/Logger.hpp"
0015 #include "Acts/Utilities/Result.hpp"
0016 
0017 #include <exception>
0018 #include <memory>
0019 #include <span>
0020 #include <string>
0021 #include <vector>
0022 
0023 namespace Acts {
0024 
0025 class RegularSurface;
0026 class GeometryContext;
0027 class TrackingVolume;
0028 class CylinderSurface;
0029 class PlaneSurface;
0030 class DiscSurface;
0031 class Surface;
0032 
0033 class PortalLinkBase;
0034 
0035 /// Exception thrown when portals cannot be merged
0036 class PortalMergingException : public std::exception {
0037  public:
0038   /// Default constructor producing a generic message.
0039   PortalMergingException() = default;
0040   /// Construct with a contextual message describing why the merge failed.
0041   /// @param message The contextual error message
0042   explicit PortalMergingException(std::string message);
0043   /// Get exception description.
0044   /// @return C-style string describing the exception
0045   const char* what() const noexcept override;
0046 
0047  private:
0048   std::string m_message{"Failure to merge portals"};
0049 };
0050 
0051 /// Exception thrown when portals cannot be fused
0052 class PortalFusingException : public std::exception {
0053   const char* what() const noexcept override;
0054 };
0055 
0056 /// Policy controlling how @ref Acts::Portal::merge treats surfaces that carry
0057 /// material. Merged surfaces cannot retain the material of their inputs, so by
0058 /// default this is treated as a fatal error.
0059 enum class PortalMaterialMergePolicy {
0060   /// Abort the merge by throwing a @ref PortalMergingException (default).
0061   eThrow,
0062   /// Continue the merge: discard the input material, tag the merged surface
0063   /// with a @ref MergedMaterialMarker and emit a warning. This is lossy.
0064   eDiscardAndMark,
0065 };
0066 
0067 /// A portal connects two or more neighboring volumes. Each volume has a set of
0068 /// portals that describes which volumes lie behind the portal in that
0069 /// direction. Portals use associated portal links to perform lookups of target
0070 /// volumes.
0071 /// Each portal has two links (at least one non-null), and a corresponding
0072 /// surface. One link is associated with the direction along the surface's
0073 /// normal vector, and one with the opposite direction.
0074 class Portal {
0075  public:
0076   /// Constructor for a portal from a single link
0077   /// @param direction The direction of the link
0078   /// @param link The portal link
0079   Portal(Direction direction, std::unique_ptr<PortalLinkBase> link);
0080 
0081   /// Constructor for a portal from a surface and volume, where a trivial portal
0082   /// link is automatically constructed.
0083   /// @param direction The direction of the link
0084   /// @param surface The surface from which to create the portal link
0085   /// @param volume The volume this portal connects to in the @p direction
0086   ///               relative to the normal of @p surface.
0087   Portal(Direction direction, std::shared_ptr<RegularSurface> surface,
0088          TrackingVolume& volume);
0089 
0090   /// Constructor for a portal from two links. One of the links can be
0091   /// `nullptr`, but at least one of them needs to be set. If both are set, they
0092   /// need to be valid compatible links that can be fused.
0093   /// @param gctx The geometry context
0094   /// @param alongNormal The link along the normal of the surface
0095   /// @param oppositeNormal The link opposite to the normal of the
0096   Portal(const GeometryContext& gctx,
0097          std::unique_ptr<PortalLinkBase> alongNormal,
0098          std::unique_ptr<PortalLinkBase> oppositeNormal);
0099 
0100   /// Helper struct for the arguments to the portal constructor below using
0101   /// designated initializers.
0102   struct Arguments {
0103     /// Aggregate over a surface and a volume with optional semantics
0104     struct Link {
0105       Link() = default;
0106       /// Constructor from a surface and a volume
0107       /// @param surfaceIn Surface to associate with this link
0108       /// @param volumeIn Volume to associate with this link
0109       Link(std::shared_ptr<RegularSurface> surfaceIn, TrackingVolume& volumeIn)
0110           : surface(std::move(surfaceIn)), volume(&volumeIn) {}
0111 
0112       /// The associated surface
0113       std::shared_ptr<RegularSurface> surface = nullptr;
0114       /// The associated volume
0115       TrackingVolume* volume = nullptr;
0116     };
0117 
0118     /// Entry for the link along normal
0119     Link alongNormal{};
0120     /// Entry for the link opposite normal
0121     Link oppositeNormal{};
0122   };
0123 
0124   /// Constructor that takes a geometry context and an rvalue reference to a
0125   /// helper struct from above. This pattern allows you to use designated
0126   /// initializers to construct this object like:
0127   /// ```cpp
0128   /// Portal{gctx, {.oppositeNormal = {cyl1, *vol1}}};
0129   /// Portal{gctx, {.alongNormal = {cyl2, *vol2}}};
0130   /// ```
0131   /// @param gctx The geometry context
0132   /// @param args The struct containing the arguments
0133   Portal(const GeometryContext& gctx, Arguments&& args);
0134 
0135   /// Fuse two portals together. Fusing is the combination of two portal links
0136   /// on the same logical surfaces. The actual surface instances can be
0137   /// different, as long as they are geometrically equivalent (within numerical
0138   /// precision). The resulting portal will have one portal along the shared
0139   /// surface's normal vector, and one opposite that vector.
0140   ///
0141   /// ```
0142   ///    portal1   portal2
0143   ///      +---+   +---+
0144   ///      |   |   |   |
0145   ///      |   |   |   |
0146   /// <----+   | + |   +---->
0147   ///      |   |   |   |
0148   ///      |   |   |   |
0149   ///      +---+   +---+
0150   /// ```
0151   ///
0152   /// @note The input portals need to have compatible link loadaout, e.g. one
0153   ///       portal needs to have the *along normal* slot filled, and the
0154   ///       otherone one needs to have the *opposite normal* slot filled. If
0155   ///       portals share a filled slot, the function throws an exception.
0156   /// @note This is a destructive operation on the portals involved
0157   /// @param gctx The geometry context
0158   /// @param aPortal The first portal
0159   /// @param bPortal The second portal
0160   /// @param logger The logger to push output to
0161   /// @return A new portal that combines both input portals
0162   static Portal fuse(const GeometryContext& gctx, Portal& aPortal,
0163                      Portal& bPortal, const Logger& logger = getDummyLogger());
0164 
0165   /// Merge two adjacent portals with each other to produce a new portal that
0166   /// encompasses both inputs. It is the complementary operation to the fusing
0167   /// of portals. To be able to merge portals, the surfaces of their associated
0168   /// links need to be *mergeable*, and the portal links need to be compatible.
0169   /// This means that both portals need to have a link along the portal surface
0170   /// normal, opposite the normal, or both. If the equipped links are opposite
0171   /// relative to one another (e.g. one along one opposite), the function will
0172   /// throw an exception.
0173   ///
0174   /// ```
0175   ///         ^                     ^
0176   ///         |                     |
0177   ///  portal1|              portal2|
0178   /// +-------+-------+     +-------+-------+
0179   /// |               |  +  |               |
0180   /// +-------+-------+     +-------+-------+
0181   ///         |                     |
0182   ///         |                     |
0183   ///         v                     v
0184   /// ```
0185   ///
0186   /// @note This is a destructive operation on both portals, their
0187   ///       links will be moved to produce merged links, which can fail
0188   ///       if the portal links are not compatible
0189   /// @param gctx The geometry context
0190   /// @param aPortal The first portal
0191   /// @param bPortal The second portal
0192   /// @param direction The direction of the merge (e.g. along z)
0193   /// @param logger The logger to push output to
0194   /// @param materialPolicy How to treat surfaces that carry material. By
0195   ///        default the merge aborts with an exception; in
0196   ///        @ref PortalMaterialMergePolicy::eDiscardAndMark mode the material is
0197   ///        discarded, the merged surface is tagged with a
0198   ///        @ref MergedMaterialMarker and a warning is emitted.
0199   /// @return A new merged portal that encompasses both input portals
0200   static Portal merge(const GeometryContext& gctx, Portal& aPortal,
0201                       Portal& bPortal, AxisDirection direction,
0202                       const Logger& logger = getDummyLogger(),
0203                       PortalMaterialMergePolicy materialPolicy =
0204                           PortalMaterialMergePolicy::eThrow);
0205 
0206   /// Resolve the volume for a 3D position and a direction
0207   /// The @p direction is used to select the right portal link, if it is set.
0208   /// In case no link is found in the specified direction, a `nullptr` is
0209   /// returned.
0210   /// @param gctx The geometry context
0211   /// @param position The 3D position
0212   /// @param direction The direction
0213   /// @return The target volume (can be `nullptr`)
0214   Result<const TrackingVolume*> resolveVolume(const GeometryContext& gctx,
0215                                               const Vector3& position,
0216                                               const Vector3& direction) const;
0217 
0218   /// Set a link on the portal into the slot specified by the direction.
0219   /// @note The surface associated with @p link must be logically equivalent
0220   ///       to the one of the link that's already set on the portal.
0221   /// @param gctx The geometry context
0222   /// @param direction The direction
0223   /// @param link The link to set
0224   void setLink(const GeometryContext& gctx, Direction direction,
0225                std::unique_ptr<PortalLinkBase> link);
0226 
0227   /// Helper function create a trivial portal link based on a surface.
0228   /// @param gctx The geometry context
0229   /// @param direction The direction of the link to create
0230   /// @param surface The surface
0231   /// @note The @p surface must be logically equivalent
0232   ///       to the one of the link that's already set on the portal.
0233   /// @param volume The target volume
0234   void setLink(const GeometryContext& gctx, Direction direction,
0235                std::shared_ptr<RegularSurface> surface, TrackingVolume& volume);
0236 
0237   /// Get the link associated with the @p direction. Can be null if the associated link is unset.
0238   /// @param direction The direction
0239   /// @return The link (can be null)
0240   const PortalLinkBase* getLink(Direction direction) const;
0241 
0242   /// Returns true if the portal is valid, that means it has at least one
0243   /// non-null link associated.Portals can be in an invalid state after they get
0244   /// merged or fused with other portals.
0245   /// @return True if the portal is valid
0246   bool isValid() const;
0247 
0248   /// Create and attach a trivial portal link to the empty slot of this portal
0249   /// @param volume The target volume to connect to
0250   void fill(TrackingVolume& volume);
0251 
0252   /// Access the portal surface that is shared between the two links
0253   /// @return The portal surface
0254   const RegularSurface& surface() const;
0255 
0256   /// Access the portal surface that is shared between the two links
0257   /// @return The portal surface
0258   RegularSurface& surface();
0259 
0260   /// Add a string tag to this portal. Tags are used to look the portal up from
0261   /// the final @ref Acts::TrackingGeometry (e.g. the portal connecting the
0262   /// tracker and the calorimeter).
0263   /// @param tag The tag to add
0264   void addTag(std::string tag);
0265 
0266   /// Access the tags assigned to this portal.
0267   /// @return A view of the tags assigned to this portal
0268   std::span<const std::string> tags() const;
0269 
0270  private:
0271   /// Helper to check surface equivalence without checking material status. This
0272   /// is needed because we allow fusing portals with surfaces that are
0273   /// equivalent but one of them has material while the other does not. The
0274   /// normal surface comparison would determine these surfaces as not
0275   /// equivalent.
0276   /// @param gctx The geometry context
0277   /// @param a The first surface
0278   /// @param b The second surface
0279   /// @return True if the surfaces are equivalent
0280   static bool isSameSurface(const GeometryContext& gctx, const Surface& a,
0281                             const Surface& b);
0282 
0283   std::shared_ptr<RegularSurface> m_surface;
0284 
0285   std::unique_ptr<PortalLinkBase> m_alongNormal;
0286   std::unique_ptr<PortalLinkBase> m_oppositeNormal;
0287 
0288   std::vector<std::string> m_tags;
0289 };
0290 
0291 }  // namespace Acts