Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 10:09:33

0001 //----------------------------------*-C++-*----------------------------------//
0002 // Copyright 2020-2024 UT-Battelle, LLC, and other Celeritas developers.
0003 // See the top-level COPYRIGHT file for details.
0004 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0005 //---------------------------------------------------------------------------//
0006 //! \file geocel/vg/VecgeomTrackView.hh
0007 //---------------------------------------------------------------------------//
0008 #pragma once
0009 
0010 #include <VecGeom/base/Config.h>
0011 #include <VecGeom/base/Cuda.h>
0012 #include <VecGeom/base/Version.h>
0013 #include <VecGeom/navigation/NavStateFwd.h>
0014 #include <VecGeom/navigation/NavigationState.h>
0015 #include <VecGeom/volumes/LogicalVolume.h>
0016 #include <VecGeom/volumes/PlacedVolume.h>
0017 
0018 #include "corecel/Macros.hh"
0019 #include "corecel/math/Algorithms.hh"
0020 #include "corecel/math/ArrayUtils.hh"
0021 #include "corecel/math/SoftEqual.hh"
0022 #include "geocel/Types.hh"
0023 
0024 #include "VecgeomData.hh"
0025 
0026 #include "detail/VecgeomCompatibility.hh"
0027 
0028 #if VECGEOM_VERSION < 0x020000
0029 #    include "detail/BVHNavigator.hh"
0030 #elif defined(VECGEOM_USE_SURF)
0031 #    include "detail/SurfNavigator.hh"
0032 #else
0033 #    include <VecGeom/navigation/BVHNavigator.h>
0034 #endif
0035 
0036 namespace celeritas
0037 {
0038 //---------------------------------------------------------------------------//
0039 /*!
0040  * Navigate through a VecGeom geometry on a single thread.
0041  *
0042  * For a description of ordering requirements, see:
0043  * \sa OrangeTrackView
0044  *
0045  * \code
0046     VecgeomTrackView geom(vg_params_ref, vg_state_ref, trackslot_id);
0047    \endcode
0048  *
0049  * The "next distance" is cached as part of `find_next_step`, but it is only
0050  * used when the immediate next call is `move_to_boundary`.
0051  */
0052 class VecgeomTrackView
0053 {
0054   public:
0055     //!@{
0056     //! \name Type aliases
0057     using Initializer_t = GeoTrackInitializer;
0058     using ParamsRef = NativeCRef<VecgeomParamsData>;
0059     using StateRef = NativeRef<VecgeomStateData>;
0060 #if VECGEOM_VERSION < 0x020000
0061     using Navigator = celeritas::detail::BVHNavigator;
0062 #elif defined(VECGEOM_USE_SURF)
0063     using Navigator = celeritas::detail::SurfNavigator;
0064 #else
0065     using Navigator = vecgeom::BVHNavigator;
0066 #endif
0067     //!@}
0068 
0069     //! Helper struct for initializing from an existing geometry state
0070     struct DetailedInitializer
0071     {
0072         VecgeomTrackView const& other;  //!< Existing geometry
0073         Real3 const& dir;  //!< New direction
0074     };
0075 
0076   public:
0077     // Construct from persistent and state data
0078     inline CELER_FUNCTION VecgeomTrackView(ParamsRef const& data,
0079                                            StateRef const& stateview,
0080                                            TrackSlotId tid);
0081 
0082     // Initialize the state
0083     inline CELER_FUNCTION VecgeomTrackView&
0084     operator=(Initializer_t const& init);
0085     // Initialize the state from a parent state and new direction
0086     inline CELER_FUNCTION VecgeomTrackView&
0087     operator=(DetailedInitializer const& init);
0088 
0089     //// STATIC ACCESSORS ////
0090 
0091     //! A tiny push to make sure tracks do not get stuck at boundaries
0092     static CELER_CONSTEXPR_FUNCTION real_type extra_push() { return 1e-13; }
0093 
0094     //// ACCESSORS ////
0095 
0096     //!@{
0097     //! State accessors
0098     CELER_FORCEINLINE_FUNCTION Real3 const& pos() const { return pos_; }
0099     CELER_FORCEINLINE_FUNCTION Real3 const& dir() const { return dir_; }
0100     //!@}
0101 
0102     // Get the volume ID in the current cell.
0103     CELER_FORCEINLINE_FUNCTION VolumeId volume_id() const;
0104     CELER_FORCEINLINE_FUNCTION int volume_physid() const;
0105 
0106     //!@{
0107     //! VecGeom states are never "on" a surface
0108     CELER_FUNCTION SurfaceId surface_id() const { return {}; }
0109     //!@}
0110 
0111     // Whether the track is outside the valid geometry region
0112     CELER_FORCEINLINE_FUNCTION bool is_outside() const;
0113     // Whether the track is exactly on a surface
0114     CELER_FORCEINLINE_FUNCTION bool is_on_boundary() const;
0115     //! Whether the last operation resulted in an error
0116     CELER_FORCEINLINE_FUNCTION bool failed() const { return false; }
0117 
0118     //// OPERATIONS ////
0119 
0120     // Find the distance to the next boundary (infinite max)
0121     inline CELER_FUNCTION Propagation find_next_step();
0122 
0123     // Find the distance to the next boundary, up to and including a step
0124     inline CELER_FUNCTION Propagation find_next_step(real_type max_step);
0125 
0126     // Find the safety at the current position (infinite max)
0127     inline CELER_FUNCTION real_type find_safety();
0128 
0129     // Find the safety at the current position up to a maximum step distance
0130     inline CELER_FUNCTION real_type find_safety(real_type max_step);
0131 
0132     // Move to the boundary in preparation for crossing it
0133     inline CELER_FUNCTION void move_to_boundary();
0134 
0135     // Move within the volume
0136     inline CELER_FUNCTION void move_internal(real_type step);
0137 
0138     // Move within the volume to a specific point
0139     inline CELER_FUNCTION void move_internal(Real3 const& pos);
0140 
0141     // Cross from one side of the current surface to the other
0142     inline CELER_FUNCTION void cross_boundary();
0143 
0144     // Change direction
0145     inline CELER_FUNCTION void set_dir(Real3 const& newdir);
0146 
0147   private:
0148     //// TYPES ////
0149 
0150     using Volume = vecgeom::LogicalVolume;
0151     using NavState = vecgeom::NavigationState;
0152 
0153     //// DATA ////
0154 
0155     //! Shared/persistent geometry data
0156     ParamsRef const& params_;
0157 
0158     //!@{
0159     //! Referenced thread-local data
0160     NavState& vgstate_;
0161     NavState& vgnext_;
0162     Real3& pos_;
0163     Real3& dir_;
0164     //!@}
0165 
0166     // Temporary data
0167     real_type next_step_{0};
0168 
0169     //// HELPER FUNCTIONS ////
0170 
0171     // Whether any next distance-to-boundary has been found
0172     inline CELER_FUNCTION bool has_next_step() const;
0173 
0174     // Whether the next distance-to-boundary is to a surface
0175     inline CELER_FUNCTION bool is_next_boundary() const;
0176 
0177     //! Get a reference to the current volume
0178     inline CELER_FUNCTION Volume const& volume() const;
0179 };
0180 
0181 //---------------------------------------------------------------------------//
0182 // INLINE DEFINITIONS
0183 //---------------------------------------------------------------------------//
0184 /*!
0185  * Construct from persistent and state data.
0186  */
0187 CELER_FUNCTION
0188 VecgeomTrackView::VecgeomTrackView(ParamsRef const& params,
0189                                    StateRef const& states,
0190                                    TrackSlotId tid)
0191     : params_(params)
0192     , vgstate_(states.vgstate.at(params_.max_depth, tid))
0193     , vgnext_(states.vgnext.at(params_.max_depth, tid))
0194     , pos_(states.pos[tid])
0195     , dir_(states.dir[tid])
0196 {
0197 }
0198 
0199 //---------------------------------------------------------------------------//
0200 /*!
0201  * Construct the state.
0202  *
0203  * Expensive. This function should only be called to initialize an event from a
0204  * starting location and direction, but excess secondaries will also be
0205  * initialized this way.
0206  */
0207 CELER_FUNCTION VecgeomTrackView&
0208 VecgeomTrackView::operator=(Initializer_t const& init)
0209 {
0210     CELER_EXPECT(is_soft_unit_vector(init.dir));
0211 
0212     // Initialize position/direction
0213     pos_ = init.pos;
0214     dir_ = init.dir;
0215 
0216     // Set up current state and locate daughter volume.
0217     vgstate_.Clear();
0218     vecgeom::VPlacedVolume const* worldvol = params_.world_volume;
0219     bool const contains_point = true;
0220 
0221     // LocatePointIn sets `vgstate_`
0222     Navigator::LocatePointIn(
0223         worldvol, detail::to_vector(pos_), vgstate_, contains_point);
0224 
0225     return *this;
0226 }
0227 
0228 //---------------------------------------------------------------------------//
0229 /*!
0230  * Construct the state from a direction and a copy of the parent state.
0231  *
0232  * This is a faster method of creating secondaries from a parent that has just
0233  * been absorbed, or when filling in an empty track from a parent that is still
0234  * alive.
0235  */
0236 CELER_FUNCTION
0237 VecgeomTrackView& VecgeomTrackView::operator=(DetailedInitializer const& init)
0238 {
0239     CELER_EXPECT(is_soft_unit_vector(init.dir));
0240 
0241     if (this != &init.other)
0242     {
0243         // Copy the navigation state and position from the parent state
0244         init.other.vgstate_.CopyTo(&vgstate_);
0245         pos_ = init.other.pos_;
0246     }
0247 
0248     // Set up the next state and initialize the direction
0249     dir_ = init.dir;
0250 
0251     CELER_ENSURE(!this->has_next_step());
0252     return *this;
0253 }
0254 
0255 //---------------------------------------------------------------------------//
0256 /*!
0257  * Get the volume ID in the current cell.
0258  */
0259 CELER_FUNCTION VolumeId VecgeomTrackView::volume_id() const
0260 {
0261     CELER_EXPECT(!this->is_outside());
0262     return VolumeId{this->volume().id()};
0263 }
0264 
0265 //---------------------------------------------------------------------------//
0266 /*!
0267  * Get the physical volume ID in the current cell.
0268  */
0269 CELER_FUNCTION int VecgeomTrackView::volume_physid() const
0270 {
0271     CELER_EXPECT(!this->is_outside());
0272     return this->vgstate_.Top()->id();
0273 }
0274 
0275 //---------------------------------------------------------------------------//
0276 /*!
0277  * Whether the track is outside the valid geometry region.
0278  */
0279 CELER_FUNCTION bool VecgeomTrackView::is_outside() const
0280 {
0281     return vgstate_.IsOutside();
0282 }
0283 
0284 //---------------------------------------------------------------------------//
0285 /*!
0286  * Whether the track is on the boundary of a volume.
0287  */
0288 CELER_FUNCTION bool VecgeomTrackView::is_on_boundary() const
0289 {
0290     return vgstate_.IsOnBoundary();
0291 }
0292 
0293 //---------------------------------------------------------------------------//
0294 /*!
0295  * Find the distance to the next geometric boundary.
0296  *
0297  * This function is allowed to be allowed to be called from the exterior for
0298  * ray tracing.
0299  */
0300 CELER_FUNCTION Propagation VecgeomTrackView::find_next_step()
0301 {
0302     if (this->is_outside())
0303     {
0304         // Find distance to interior from outside world volume
0305         auto* pplvol = params_.world_volume;
0306         next_step_ = pplvol->DistanceToIn(detail::to_vector(pos_),
0307                                           detail::to_vector(dir_),
0308                                           vecgeom::kInfLength);
0309 
0310         vgnext_.Clear();
0311         vgnext_.Push(pplvol);
0312         vgnext_.SetBoundaryState(true);
0313         next_step_ = max(next_step_, this->extra_push());
0314 
0315         Propagation result;
0316         result.distance = next_step_;
0317         result.boundary = next_step_ < vecgeom::kInfLength;
0318         return result;
0319     }
0320 
0321     return this->find_next_step(vecgeom::kInfLength);
0322 }
0323 
0324 //---------------------------------------------------------------------------//
0325 /*!
0326  * Find the distance to the next geometric boundary.
0327  */
0328 CELER_FUNCTION Propagation VecgeomTrackView::find_next_step(real_type max_step)
0329 {
0330     CELER_EXPECT(!this->is_outside());
0331     CELER_EXPECT(max_step > 0);
0332 
0333     // Use the navigator to find internal distance
0334     next_step_ = Navigator::ComputeStepAndNextVolume(detail::to_vector(pos_),
0335                                                      detail::to_vector(dir_),
0336                                                      max_step,
0337                                                      vgstate_,
0338                                                      vgnext_);
0339     next_step_ = max(next_step_, this->extra_push());
0340 
0341     if (!this->is_next_boundary())
0342     {
0343         // Soft equivalence between distance and max step is because the
0344         // BVH navigator subtracts and then re-adds a bump distance to the
0345         // step
0346         CELER_ASSERT(soft_equal(next_step_, max_step));
0347         next_step_ = max_step;
0348     }
0349 
0350     Propagation result;
0351     result.distance = next_step_;
0352     result.boundary = this->is_next_boundary();
0353 
0354     CELER_ENSURE(this->has_next_step());
0355     CELER_ENSURE(result.distance > 0);
0356     CELER_ENSURE(result.distance <= max(max_step, this->extra_push()));
0357     CELER_ENSURE(result.boundary || result.distance == max_step
0358                  || max_step < this->extra_push());
0359     return result;
0360 }
0361 
0362 //---------------------------------------------------------------------------//
0363 /*!
0364  * Find the safety at the current position.
0365  */
0366 CELER_FUNCTION real_type VecgeomTrackView::find_safety()
0367 {
0368     return this->find_safety(vecgeom::kInfLength);
0369 }
0370 
0371 //---------------------------------------------------------------------------//
0372 /*!
0373  * Find the safety at the current position up to a maximum distance.
0374  *
0375  * The safety within a step is only needed up to the end of the physics step
0376  * length.
0377  */
0378 CELER_FUNCTION real_type VecgeomTrackView::find_safety(real_type max_radius)
0379 {
0380     CELER_EXPECT(!this->is_outside());
0381     CELER_EXPECT(!this->is_on_boundary());
0382     CELER_EXPECT(max_radius > 0);
0383 
0384     real_type safety
0385         = Navigator::ComputeSafety(detail::to_vector(this->pos()), vgstate_);
0386     safety = min<real_type>(safety, max_radius);
0387 
0388     // Since the reported "safety" is negative if we've moved slightly beyond
0389     // the boundary of a solid without crossing it, we must clamp to zero.
0390     return max<real_type>(safety, 0);
0391 }
0392 
0393 //---------------------------------------------------------------------------//
0394 /*!
0395  * Move to the next boundary but don't cross yet.
0396  */
0397 CELER_FUNCTION void VecgeomTrackView::move_to_boundary()
0398 {
0399     CELER_EXPECT(this->has_next_step());
0400     CELER_EXPECT(this->is_next_boundary());
0401 
0402     // Move next step
0403     axpy(next_step_, dir_, &pos_);
0404     next_step_ = 0;
0405     vgstate_.SetBoundaryState(true);
0406 
0407     CELER_ENSURE(this->is_on_boundary());
0408 }
0409 
0410 //---------------------------------------------------------------------------//
0411 /*!
0412  * Cross from one side of the current surface to the other.
0413  *
0414  * The position *must* be on the boundary following a move-to-boundary.
0415  */
0416 CELER_FUNCTION void VecgeomTrackView::cross_boundary()
0417 {
0418     CELER_EXPECT(this->is_on_boundary());
0419     CELER_EXPECT(this->is_next_boundary());
0420 
0421     // Relocate to next tracking volume (maybe across multiple boundaries)
0422     if (vgnext_.Top() != nullptr)
0423     {
0424         // Some navigators require an lvalue temp_pos
0425         auto temp_pos = detail::to_vector(this->pos_);
0426         Navigator::RelocateToNextVolume(
0427             temp_pos, detail::to_vector(this->dir_), vgnext_);
0428     }
0429 
0430     vgstate_ = vgnext_;
0431 
0432     CELER_ENSURE(this->is_on_boundary());
0433 }
0434 
0435 //---------------------------------------------------------------------------//
0436 /*!
0437  * Move within the current volume.
0438  *
0439  * The straight-line distance *must* be less than the distance to the
0440  * boundary.
0441  */
0442 CELER_FUNCTION void VecgeomTrackView::move_internal(real_type dist)
0443 {
0444     CELER_EXPECT(this->has_next_step());
0445     CELER_EXPECT(dist > 0 && dist <= next_step_);
0446     CELER_EXPECT(dist != next_step_ || !this->is_next_boundary());
0447 
0448     // Move and update next_step_
0449     axpy(dist, dir_, &pos_);
0450     next_step_ -= dist;
0451     vgstate_.SetBoundaryState(false);
0452 
0453     CELER_ENSURE(!this->is_on_boundary());
0454 }
0455 
0456 //---------------------------------------------------------------------------//
0457 /*!
0458  * Move within the current volume to a nearby point.
0459  *
0460  * \warning It's up to the caller to make sure that the position is
0461  * "nearby" and within the same volume.
0462  */
0463 CELER_FUNCTION void VecgeomTrackView::move_internal(Real3 const& pos)
0464 {
0465     pos_ = pos;
0466     next_step_ = 0;
0467     vgstate_.SetBoundaryState(false);
0468 
0469     CELER_ENSURE(!this->is_on_boundary());
0470 }
0471 
0472 //---------------------------------------------------------------------------//
0473 /*!
0474  * Change the track's direction.
0475  *
0476  * This happens after a scattering event or movement inside a magnetic field.
0477  * It resets the calculated distance-to-boundary.
0478  */
0479 CELER_FUNCTION void VecgeomTrackView::set_dir(Real3 const& newdir)
0480 {
0481     CELER_EXPECT(is_soft_unit_vector(newdir));
0482     dir_ = newdir;
0483     next_step_ = 0;
0484 }
0485 
0486 //---------------------------------------------------------------------------//
0487 // PRIVATE MEMBER FUNCTIONS
0488 //---------------------------------------------------------------------------//
0489 /*!
0490  * Whether a next step has been calculated.
0491  */
0492 CELER_FUNCTION bool VecgeomTrackView::has_next_step() const
0493 {
0494     return next_step_ != 0;
0495 }
0496 
0497 //---------------------------------------------------------------------------//
0498 /*!
0499  * Whether a next step has been calculated.
0500  */
0501 CELER_FUNCTION bool VecgeomTrackView::is_next_boundary() const
0502 {
0503     CELER_EXPECT(this->has_next_step() || this->is_on_boundary());
0504     return vgnext_.IsOnBoundary();
0505 }
0506 
0507 //---------------------------------------------------------------------------//
0508 /*!
0509  * Get a reference to the current volume, or to world volume if outside.
0510  */
0511 CELER_FUNCTION auto VecgeomTrackView::volume() const -> Volume const&
0512 {
0513     vecgeom::VPlacedVolume const* physvol_ptr = vgstate_.Top();
0514     CELER_ENSURE(physvol_ptr);
0515     return *physvol_ptr->GetLogicalVolume();
0516 }
0517 
0518 //---------------------------------------------------------------------------//
0519 }  // namespace celeritas