Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-09 10:21:12

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 geocel/vg/VgBasicTrackView.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include "corecel/Config.hh"
0010 
0011 #if CELERITAS_VECGEOM_VERSION < 0x020200
0012 #    error "This file requires VecGeom 2.2+"
0013 #endif
0014 
0015 #include <VecGeom/navigation/NavView.h>
0016 
0017 #include "corecel/Assert.hh"
0018 #include "corecel/Macros.hh"
0019 #include "corecel/Types.hh"
0020 #include "corecel/cont/Span.hh"
0021 #include "corecel/math/ArraySoftUnit.hh"
0022 #include "corecel/sys/ThreadId.hh"
0023 #include "geocel/Types.hh"
0024 
0025 #include "VecgeomData.hh"
0026 #include "VecgeomTypes.hh"
0027 
0028 #if !CELER_DEVICE_COMPILE
0029 #    include "corecel/io/Logger.hh"
0030 #    include "corecel/io/Repr.hh"
0031 #    include "geocel/detail/LengthUnits.hh"
0032 #endif
0033 
0034 namespace celeritas
0035 {
0036 //---------------------------------------------------------------------------//
0037 /*!
0038  * Wrap basic navigation functionality from VecGeom.
0039  *
0040  * This is a transitional interface between the more full-featured
0041  * VecgeomTrackView and the new NavView that lives in VecGeom.
0042  *
0043  * \par Removed
0044  *
0045  * - Mapping of Geant4 volumes
0046  * - Ability to call \c move_to_boundary without providing the distance
0047  *   previously calculated (this will later be passed from the main stepping
0048  *   loop)
0049  * - Assertion checking of the internal movement compared to last found (this
0050  *   will rely on CheckedGeoTrackView)
0051  *
0052  * \par Example
0053  *
0054  * \code
0055     VgBasicTrackView geom(vg_params_ref, vg_state_ref, trackslot_id);
0056    \endcode
0057  */
0058 class VgBasicTrackView
0059 {
0060   public:
0061     //!@{
0062     //! \name Type aliases
0063     using Initializer_t = GeoTrackInitializer;
0064     using ParamsRef = NativeCRef<VecgeomParamsData>;
0065     using StateRef = NativeRef<VecgeomStateData>;
0066     using NavView = vecgeom::NavView;
0067     using OpaquePath = NavView::OpaquePath;
0068     using real_type = vg_real_type;
0069     using ImplVolInstanceId = VgVolumeInstanceId;
0070     //!@}
0071 
0072   public:
0073     // Construct from persistent and state data
0074     inline CELER_FUNCTION VgBasicTrackView(
0075         ParamsRef const& data, StateRef const& stateview, TrackSlotId tid);
0076 
0077     // Initialize the state
0078     inline CELER_FUNCTION VgBasicTrackView& operator=(
0079         Initializer_t const& init);
0080 
0081     //// ACCESSORS ////
0082 
0083     //!@{
0084     //! State accessors
0085     CELER_FORCEINLINE_FUNCTION Real3 const& pos() const { return pos_; }
0086     CELER_FORCEINLINE_FUNCTION Real3 const& dir() const { return dir_; }
0087     //!@}
0088 
0089     // Get the canonical volume ID in the current impl volume
0090     inline CELER_FUNCTION VolumeId volume_id() const;
0091     // Get the ID of the current volume instance
0092     inline CELER_FUNCTION VolumeInstanceId volume_instance_id() const;
0093     // Get the depth in the geometry hierarchy
0094     inline CELER_FUNCTION VolumeLevelId volume_level() const;
0095     // Get the volume instance ID for all levels
0096     inline CELER_FUNCTION void volume_instance_id(
0097         Span<VolumeInstanceId> levels) const;
0098     // Visit every volume instance in the track's path, including world
0099     template<class F>
0100     inline CELER_FUNCTION void foreach_volume_path(F&& visit) const;
0101 
0102     // Get the current volume's ID
0103     inline CELER_FUNCTION ImplVolumeId impl_volume_id() const;
0104 
0105     // Get the opaque nav path (index or tuple)
0106     inline CELER_FUNCTION OpaquePath opaque_path() const;
0107 
0108     // Whether the track is outside the valid geometry region
0109     inline CELER_FUNCTION bool is_outside() const;
0110     // Whether the track is exactly on a surface
0111     inline CELER_FUNCTION bool is_on_boundary() const;
0112     //! Whether the last operation resulted in an error
0113     CELER_FORCEINLINE_FUNCTION bool failed() const { return failed_; }
0114     // Get the normal vector of the current surface
0115     inline CELER_FUNCTION Real3 normal() const;
0116 
0117     //// OPERATIONS ////
0118 
0119     // Find the distance to the next boundary, up to and including a step
0120     inline CELER_FUNCTION Propagation find_next_step(real_type max_step);
0121 
0122     // Find the safety at the current position up to a maximum step distance
0123     inline CELER_FUNCTION real_type find_safety(real_type max_step);
0124 
0125     // Move to the boundary in preparation for crossing it
0126     inline CELER_FUNCTION void move_to_boundary(real_type step);
0127 
0128     // Move within the volume
0129     inline CELER_FUNCTION void move_internal(real_type step);
0130 
0131     // Move within the volume to a specific point
0132     inline CELER_FUNCTION void move_internal(Real3 const& pos);
0133 
0134     // Cross from one side of the current surface to the other
0135     inline CELER_FUNCTION void cross_boundary();
0136 
0137     // Change direction
0138     inline CELER_FUNCTION void set_dir(Real3 const& newdir);
0139 
0140   private:
0141     //// TYPES ////
0142 
0143     using VgLogVol = VgLogicalVolume<MemSpace::native>;
0144     using VgPlacedVol = VgPlacedVolume<MemSpace::native>;
0145 
0146     //// DATA ////
0147 
0148     //! Shared/persistent geometry data
0149     ParamsRef const& params_;
0150     StateRef const& state_;
0151     TrackSlotId tid_;
0152 
0153     //!@{
0154     //! Referenced thread-local data
0155     VgNavState& vgstate_;
0156     VgNavState& vgnext_;
0157     Real3& pos_;
0158     Real3& dir_;
0159 
0160     //!@}
0161 
0162     // Temporary data
0163     bool failed_{false};
0164 
0165     //// HELPER CLASSES ////
0166 
0167     struct LocalNavData;
0168     class LocalNav;
0169 
0170     //// HELPER FUNCTIONS ////
0171 
0172     // Whether the next distance-to-boundary is to a surface
0173     inline CELER_FUNCTION bool is_next_boundary() const;
0174 
0175     // Get a reference to the current volume instance
0176     inline CELER_FUNCTION VgPlacedVol const& physical_volume() const;
0177 
0178     // Get a reference to the current volume
0179     inline CELER_FUNCTION VgLogVol const& logical_volume() const;
0180 
0181     // Create a temporary navigator
0182     inline CELER_FUNCTION LocalNav make_nav() const;
0183 };
0184 
0185 //---------------------------------------------------------------------------//
0186 // LOCAL NAV
0187 // This will be simplified when the upstream NavView supports true Span.
0188 //---------------------------------------------------------------------------//
0189 
0190 struct VgBasicTrackView::LocalNavData
0191 {
0192     NavView::NavSetupT nav_params;
0193     VgReal3 temp_pos;
0194     VgReal3 temp_dir;
0195 };
0196 
0197 class VgBasicTrackView::LocalNav : public LocalNavData, public vecgeom::NavView
0198 {
0199   public:
0200     explicit CELER_FUNCTION LocalNav(VgBasicTrackView& vtv)
0201         : LocalNavData{{vtv.params_.scalars.world<MemSpace::native>()},
0202                        to_vgvector(vtv.pos_),
0203                        to_vgvector(vtv.dir_)}
0204         , NavView{this->nav_params,
0205                   vtv.vgstate_,
0206                   vtv.vgnext_,
0207                   this->temp_pos,
0208                   this->temp_dir}
0209     {
0210     }
0211 };
0212 
0213 //---------------------------------------------------------------------------//
0214 // INLINE DEFINITIONS
0215 //---------------------------------------------------------------------------//
0216 /*!
0217  * Construct from persistent and state data.
0218  */
0219 CELER_FUNCTION VgBasicTrackView::VgBasicTrackView(
0220     ParamsRef const& params, StateRef const& states, TrackSlotId tid)
0221     : params_(params)
0222     , state_(states)
0223     , tid_(tid)
0224     , vgstate_{states.state[tid]}
0225     , vgnext_{states.next_state[tid]}
0226     , pos_(states.pos[tid])
0227     , dir_(states.dir[tid])
0228 {
0229 }
0230 
0231 //---------------------------------------------------------------------------//
0232 /*!
0233  * Construct the state.
0234  *
0235  * If a valid parent ID is provided, the state is constructed from a direction
0236  * and a copy of the parent state.  This is a faster method of creating
0237  * secondaries from a parent that has just been absorbed, or when filling in an
0238  * empty track from a parent that is still alive.
0239  *
0240  * Otherwise, the state is initialized from a starting location and direction,
0241  * which is expensive.
0242  */
0243 CELER_FUNCTION VgBasicTrackView& VgBasicTrackView::operator=(
0244     Initializer_t const& init)
0245 {
0246     CELER_EXPECT(is_soft_unit_vector(init.dir));
0247     failed_ = false;
0248 
0249     // Copy dir/pos: make_nav currently does array -> vgreal3 conversion
0250     dir_ = init.dir;
0251     pos_ = init.pos;
0252     auto nav = this->make_nav();
0253     if (init.parent)
0254     {
0255         VgBasicTrackView other(params_, state_, init.parent);
0256         nav.Initialize(
0257             vecgeom::FullPath{other.opaque_path(), other.is_on_boundary()},
0258             nav.temp_pos,
0259             nav.temp_dir);
0260     }
0261     else
0262     {
0263         nav.Initialize(vecgeom::UnknownPath{}, nav.temp_pos, nav.temp_dir);
0264     }
0265 
0266     if (CELER_UNLIKELY(nav.IsOutside()))
0267     {
0268 #if !CELER_DEVICE_COMPILE
0269         auto msg = CELER_LOG_LOCAL(error);
0270         msg << "Failed to initialize geometry state at " << repr(pos_) << ' '
0271             << lengthunits::native_label;
0272 #endif
0273         failed_ = true;
0274     }
0275 
0276     CELER_ENSURE(this->dir() == to_array(nav.GetDirection()));
0277     CELER_ENSURE(this->pos() == to_array(nav.GetPosition()));
0278     return *this;
0279 }
0280 
0281 //---------------------------------------------------------------------------//
0282 /*!
0283  * Get the volume ID in the current cell.
0284  */
0285 CELER_FORCEINLINE_FUNCTION ImplVolumeId VgBasicTrackView::impl_volume_id() const
0286 {
0287     CELER_EXPECT(!this->is_outside());
0288     return id_cast<ImplVolumeId>(this->logical_volume().id());
0289 }
0290 
0291 //---------------------------------------------------------------------------//
0292 /*!
0293  * After 'find_next_step', the next straight-line surface.
0294  */
0295 CELER_FORCEINLINE_FUNCTION auto VgBasicTrackView::opaque_path() const
0296     -> OpaquePath
0297 {
0298     return this->make_nav().GetOpaquePath();
0299 }
0300 
0301 //---------------------------------------------------------------------------//
0302 /*!
0303  * Whether the track is outside the valid geometry region.
0304  */
0305 CELER_FORCEINLINE_FUNCTION bool VgBasicTrackView::is_outside() const
0306 {
0307     return vgstate_.IsOutside();
0308 }
0309 
0310 //---------------------------------------------------------------------------//
0311 /*!
0312  * Whether the track is on the boundary of a volume.
0313  */
0314 CELER_FORCEINLINE_FUNCTION bool VgBasicTrackView::is_on_boundary() const
0315 {
0316     return vgstate_.IsOnBoundary();
0317 }
0318 
0319 //---------------------------------------------------------------------------//
0320 /*!
0321  * Get the surface normal of the boundary the track is currently on.
0322  */
0323 CELER_FORCEINLINE_FUNCTION Real3 VgBasicTrackView::normal() const
0324 {
0325     // TODO: not implemented in navigator yet (as of 2.1)
0326     CELER_NOT_IMPLEMENTED("calculating surface normal");
0327 }
0328 
0329 //---------------------------------------------------------------------------//
0330 /*!
0331  * Find the distance to the next geometric boundary.
0332  */
0333 CELER_FUNCTION Propagation VgBasicTrackView::find_next_step(real_type max_step)
0334 {
0335     CELER_EXPECT(!this->is_outside());
0336     CELER_EXPECT(max_step > 0);
0337 
0338     using Kind = vecgeom::NavFindResultKind;
0339 
0340     auto found = this->make_nav().FindNextBoundary(max_step);
0341 
0342     Propagation result;
0343     if (found.GetKind() == Kind::hit)
0344     {
0345         result.distance = found.GetDistance();
0346         result.boundary = true;
0347         CELER_ASSERT(found.GetDistance() < max_step);
0348     }
0349     else if (found.GetKind() == Kind::miss)
0350     {
0351         result.distance = max_step;
0352         result.boundary = false;
0353     }
0354     else if (found.GetKind() == Kind::reentrant)
0355     {
0356         result.distance = 0;
0357         result.boundary = true;
0358     }
0359     else if (CELER_UNLIKELY(found.GetKind() == Kind::error))
0360     {
0361 #if !CELER_DEVICE_COMPILE
0362         auto msg = CELER_LOG_LOCAL(debug);
0363         msg << "Failed to find next step at " << repr(pos_) << ' '
0364             << lengthunits::native_label << " along " << repr(dir_);
0365 #endif
0366         failed_ = true;
0367         result.distance = 0;
0368         result.boundary = true;
0369     }
0370     else
0371     {
0372         CELER_ASSERT_UNREACHABLE();
0373     }
0374 
0375     CELER_ENSURE(result.distance >= 0 && result.distance <= max_step);
0376     return result;
0377 }
0378 
0379 //---------------------------------------------------------------------------//
0380 /*!
0381  * Find the safety at the current position up to a maximum distance.
0382  *
0383  * The safety within a step is only needed up to the end of the physics step
0384  * length.
0385  */
0386 CELER_FUNCTION real_type VgBasicTrackView::find_safety(real_type max_radius)
0387 {
0388     CELER_EXPECT(!this->is_outside());
0389     CELER_EXPECT(!this->is_on_boundary());
0390     CELER_EXPECT(max_radius > 0);
0391 
0392     auto safety = this->make_nav().FindSafety(max_radius);
0393     CELER_ENSURE(safety >= 0 && safety <= max_radius);
0394     return safety;
0395 }
0396 
0397 //---------------------------------------------------------------------------//
0398 /*!
0399  * Move to the next boundary but don't cross yet.
0400  *
0401  * Note that, unlike the regular move_internal, we allow zero distance in this
0402  * case since it results in a change in state (though that \em may allow a
0403  * cycle).
0404  */
0405 CELER_FUNCTION void VgBasicTrackView::move_to_boundary(real_type dist)
0406 {
0407     CELER_EXPECT(dist >= 0);
0408     CELER_EXPECT(!this->is_outside());
0409     CELER_EXPECT(this->is_next_boundary());
0410 
0411     auto nav = this->make_nav();
0412     nav.MoveToBoundary(dist);
0413     pos_ = to_array(nav.GetPosition());
0414     CELER_ENSURE(this->is_on_boundary());
0415 }
0416 
0417 //---------------------------------------------------------------------------//
0418 /*!
0419  * Cross from one side of the current surface to the other.
0420  *
0421  * The position *must* be on the boundary following a move-to-boundary.
0422  */
0423 CELER_FUNCTION void VgBasicTrackView::cross_boundary()
0424 {
0425     CELER_EXPECT(!this->is_outside());
0426     CELER_EXPECT(this->is_on_boundary());
0427     CELER_EXPECT(this->is_next_boundary());
0428 
0429     this->make_nav().CrossBoundary();
0430     CELER_ENSURE(this->is_on_boundary());
0431 }
0432 
0433 //---------------------------------------------------------------------------//
0434 /*!
0435  * Move within the current volume.
0436  *
0437  * The straight-line distance *must* be less than the distance to the
0438  * boundary.
0439  */
0440 CELER_FUNCTION void VgBasicTrackView::move_internal(real_type dist)
0441 {
0442     CELER_EXPECT(dist > 0);
0443 
0444     auto nav = this->make_nav();
0445     nav.MoveInternal(dist);
0446     pos_ = to_array(nav.GetPosition());
0447 
0448     CELER_ENSURE(!this->is_on_boundary());
0449 }
0450 
0451 //---------------------------------------------------------------------------//
0452 /*!
0453  * Move within the current volume to a nearby point.
0454  *
0455  * The caller must ensure that the position is "nearby" and within the same
0456  * volume.
0457  */
0458 CELER_FUNCTION void VgBasicTrackView::move_internal(Real3 const& pos)
0459 {
0460     pos_ = pos;
0461     auto nav = this->make_nav();
0462     nav.MoveInternal(to_vgvector(pos));
0463     pos_ = to_array(nav.GetPosition());
0464     CELER_ENSURE(!this->is_on_boundary());
0465 }
0466 
0467 //---------------------------------------------------------------------------//
0468 /*!
0469  * Change the track's direction.
0470  *
0471  * This happens after a scattering event or movement inside a magnetic field.
0472  * It resets the calculated distance-to-boundary.
0473  */
0474 CELER_FUNCTION void VgBasicTrackView::set_dir(Real3 const& newdir)
0475 {
0476     CELER_EXPECT(is_soft_unit_vector(newdir));
0477     auto nav = this->make_nav();
0478     nav.ChangeDirection(to_vgvector(newdir));
0479     dir_ = to_array(nav.GetDirection());
0480 }
0481 
0482 //---------------------------------------------------------------------------//
0483 // PRIVATE MEMBER FUNCTIONS
0484 //---------------------------------------------------------------------------//
0485 /*!
0486  * Whether the calculated next step will take track to next boundary.
0487  */
0488 CELER_FORCEINLINE_FUNCTION bool VgBasicTrackView::is_next_boundary() const
0489 {
0490     return vgnext_.IsOnBoundary();
0491 }
0492 
0493 //---------------------------------------------------------------------------//
0494 /*!
0495  * Get a reference to the current volume.
0496  */
0497 CELER_FUNCTION auto VgBasicTrackView::physical_volume() const
0498     -> VgPlacedVol const&
0499 {
0500     VgPlacedVol const* physvol_ptr = vgstate_.Top();
0501     CELER_ENSURE(physvol_ptr);
0502     return *physvol_ptr;
0503 }
0504 
0505 //---------------------------------------------------------------------------//
0506 /*!
0507  * Get a reference to the current volume, or to world volume if outside.
0508  */
0509 CELER_FORCEINLINE_FUNCTION auto VgBasicTrackView::logical_volume() const
0510     -> VgLogVol const&
0511 {
0512     return *this->physical_volume().GetLogicalVolume();
0513 }
0514 
0515 // Create a temporary navigator
0516 CELER_FUNCTION auto VgBasicTrackView::make_nav() const -> LocalNav
0517 {
0518     return LocalNav{const_cast<VgBasicTrackView&>(*this)};
0519 }
0520 
0521 //---------------------------------------------------------------------------//
0522 }  // namespace celeritas