Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-07 10:11:40

0001 //------------------------------- -*- C++ -*- -------------------------------//
0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details
0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0004 //---------------------------------------------------------------------------//
0005 //! \file celeritas/optical/surface/SurfacePhysicsView.hh
0006 //! \sa celeritas/optical/SurfacePhysics.test.cc
0007 //---------------------------------------------------------------------------//
0008 #pragma once
0009 
0010 #include "celeritas/Types.hh"
0011 #include "celeritas/optical/Types.hh"
0012 
0013 #include "SurfacePhysicsData.hh"
0014 #include "SurfacePhysicsUtils.hh"
0015 
0016 namespace celeritas
0017 {
0018 namespace optical
0019 {
0020 //---------------------------------------------------------------------------//
0021 /*!
0022  * Access physics data for a local surface based on traversal orientation.
0023  *
0024  * "Local" surfaces, which are boundaries between layers on a geometric
0025  * surface, are ordered in storage between two volumes based on user input.
0026  * These layers can be traversed based on the \c orientation, whether the track
0027  * entered the surface crossing in \c forward order (e.g., \em out of the
0028  * volume defining a boundary surface) or \c reverse (e.g., \em into that
0029  * volume).
0030  *
0031  * The surface physics record only stores the behavior on the surfaces and
0032  * interstitial materials. Because one geometric surface can be surrounded by
0033  * different pairs of pre/post materials (due to the physical volume
0034  * adjacency), it \em cannot store the pre- and post-crossing materials.
0035  * Those are managed by the \c SurfacePhysicsTrackView which has extra state.
0036  *
0037  * A single geometric surface with \em N interstitial layers will have
0038  * \f$ N + 2 \f$ "local materials" and \f$ N + 1 \f$ "local surfaces".
0039  * Most geometric surfaces have no interstial layers, just a pre- and post-
0040  * volume material with a single surface, and therefore have two local material
0041  * regions surrounding a single local surface.
0042  *
0043  * During crossing \c LocalSurfaceId{0} separates the pre-volume material (\c
0044  * LocalPositionId{0} ) and the next.
0045  * Physics surface IDs are contiguous <em>by construction</em>
0046  * in the surface physics loader and optical physics input.
0047  *
0048  * \par Example traversal
0049  *
0050  * This surface record has two interstitial materials, implying three surfaces
0051  * and a total of four materials during the crossing.
0052  * The IDs and corresponding physics data, when traversing in the forward
0053  * direction, are:
0054  * \verbatim
0055   local surface ID        :       LS0   LS1    LS2
0056   local material ID       :  LM0   | LM1 | LM2  |  LM3
0057   interstitial materials  : (pre)  | IM0 | IM1  | (post)
0058   optical materials       :  ----  | A   | B    | ----
0059   physics surfaces        :        | X   | X+1  |
0060   \endverbatim
0061  * Only the two interstitial materials' optical material IDs can be accessed by
0062  * the view.
0063  * The orientation of the local surfaces and interstitial materials align
0064  * with the \c SurfacePhysicsRecord storage \em only in the \c forward
0065  * orientation.
0066  * When traversing in \c reverse  orientation, the data layout stays the same
0067  * but the IDs are still relative to the pre/post volumes:
0068  * \verbatim
0069   local surface ID        :       LS2   LS1    LS0
0070   local material ID       :  LM3   | LM2 | LM1  |  LM0
0071   interstitial materials  : (post) | IM1 | IM0  | (pre)
0072   optical materials       :  ----  | A   | B    | ----
0073   physics surfaces        :        | X   | X+1  |
0074   \endverbatim
0075  *
0076  */
0077 class SurfacePhysicsView
0078 {
0079   public:
0080     //!@{
0081     //! \name Type aliases
0082     using SurfaceParamsRef = NativeCRef<SurfacePhysicsParamsData>;
0083     //!@}
0084 
0085   public:
0086     // Construct view from data and state
0087     inline CELER_FUNCTION SurfacePhysicsView(
0088         SurfaceParamsRef const&, SurfaceId, LocalDirection);
0089 
0090     //! Get geometric surface ID the track is currently on
0091     CELER_FIF SurfaceId surface() const { return surface_; }
0092 
0093     //! Get traversal orientation on the current surface
0094     CELER_FIF LocalDirection orientation() const { return orientation_; }
0095 
0096     // Get optical pre/interstitial/post material at the given track position
0097     inline CELER_FUNCTION OptMatId interstitial_material(LocalPositionId) const;
0098 
0099     // Get the physics surface at the given position and direction
0100     inline CELER_FUNCTION PhysSurfaceId interface(LocalPositionId,
0101                                                   LocalDirection) const;
0102 
0103   private:
0104     SurfaceParamsRef const& params_;
0105     SurfaceId surface_;
0106     LocalDirection orientation_;
0107 
0108     // Get record data for the current surface
0109     inline CELER_FUNCTION SurfacePhysicsRecord const& surface_record() const;
0110 };
0111 
0112 //---------------------------------------------------------------------------//
0113 // INLINE DEFINITIONS
0114 //---------------------------------------------------------------------------//
0115 /*!
0116  * Construct from data, states, and a given track ID.
0117  */
0118 CELER_FUNCTION SurfacePhysicsView::SurfacePhysicsView(
0119     SurfaceParamsRef const& params,
0120     SurfaceId surface,
0121     LocalDirection orientation)
0122     : params_(params), surface_(surface), orientation_(orientation)
0123 {
0124     CELER_EXPECT(surface_ < params_.surfaces.size());
0125 }
0126 
0127 //---------------------------------------------------------------------------//
0128 /*!
0129  * Return the interstitial material ID at the given track position.
0130  *
0131  * Position should be in the range [1,N] where N is the number of subsurface
0132  * materials.
0133  */
0134 CELER_FUNCTION OptMatId SurfacePhysicsView::interstitial_material(
0135     LocalPositionId pos) const
0136 {
0137     auto const& ids = this->surface_record().interstitial_mat_ids;
0138     CELER_EXPECT(pos > LocalPositionId{0} && pos <= ids.size());
0139 
0140     // Position 0 is pre-volume material, and N+1 is post-volume material.
0141     // Offset position so it maps to the interstitial material range.
0142     LocalPositionId::size_type interstit_idx = pos.unchecked_get();
0143     if (orientation_ == LocalDirection::reverse)
0144     {
0145         interstit_idx = ids.size() - interstit_idx;
0146     }
0147     else
0148     {
0149         --interstit_idx;
0150     }
0151 
0152     ItemId<OptMatId> opt_mat_id_id = ids[interstit_idx];
0153     CELER_ASSERT(opt_mat_id_id < params_.opt_mat_ids.size());
0154     return params_.opt_mat_ids[opt_mat_id_id];
0155 }
0156 
0157 //---------------------------------------------------------------------------//
0158 /*!
0159  * Return the next physics surface at the given position along the direction.
0160  */
0161 CELER_FUNCTION PhysSurfaceId SurfacePhysicsView::interface(
0162     LocalPositionId pos, LocalDirection dir) const
0163 {
0164     auto const& ids = this->surface_record().local_surface_ids;
0165     CELER_EXPECT(pos >= LocalPositionId{0} && pos <= ids.size());
0166 
0167     auto local_surf = local_surf_id(pos, dir);
0168     if (orientation_ == LocalDirection::reverse)
0169     {
0170         // Reverse index in ids: 0 -> N-1; 1 -> N-2; ...
0171         local_surf = id_cast<LocalSurfaceId>(
0172             ids.size() - 1 - local_surf.unchecked_get());
0173     }
0174 
0175     CELER_ENSURE(local_surf < ids.size());
0176     return ids[local_surf];
0177 }
0178 
0179 //---------------------------------------------------------------------------//
0180 /*!
0181  * Get surface record of current geometric surface.
0182  */
0183 CELER_FUNCTION SurfacePhysicsRecord const&
0184 SurfacePhysicsView::surface_record() const
0185 {
0186     return params_.surfaces[this->surface()];
0187 }
0188 
0189 //---------------------------------------------------------------------------//
0190 }  // namespace optical
0191 }  // namespace celeritas