Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 08:54:50

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/user/detail/StepGatherExecutor.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include "corecel/Assert.hh"
0010 #include "corecel/Macros.hh"
0011 #include "corecel/Types.hh"
0012 #include "celeritas/global/CoreTrackData.hh"
0013 #include "celeritas/global/CoreTrackView.hh"
0014 
0015 namespace celeritas
0016 {
0017 namespace detail
0018 {
0019 //---------------------------------------------------------------------------//
0020 /*!
0021  * Gather step data for transfer to user hits.
0022  */
0023 template<StepPoint P>
0024 struct StepGatherExecutor
0025 {
0026     NativeCRef<StepParamsData> const params;
0027     NativeRef<StepStateData> const state;
0028 
0029     inline CELER_FUNCTION void
0030     operator()(celeritas::CoreTrackView const& track);
0031 
0032     inline CELER_FUNCTION void fill(celeritas::CoreTrackView const& track);
0033 };
0034 
0035 //---------------------------------------------------------------------------//
0036 // INLINE DEFINITIONS
0037 //---------------------------------------------------------------------------//
0038 /*!
0039  * Decide whether to fill data and fill key attributes if inactive.
0040  */
0041 template<StepPoint P>
0042 CELER_FUNCTION void
0043 StepGatherExecutor<P>::operator()(celeritas::CoreTrackView const& track)
0044 {
0045     CELER_EXPECT(params && state);
0046 
0047     {
0048         auto const sim = track.sim();
0049         bool inactive = (sim.status() == TrackStatus::inactive
0050                          || sim.status() == TrackStatus::errored);
0051 
0052         if (P == StepPoint::post)
0053         {
0054             // Always save track ID to clear output from inactive slots
0055             this->state.data.track_id[track.track_slot_id()]
0056                 = inactive ? TrackId{} : sim.track_id();
0057         }
0058 
0059         if (inactive)
0060         {
0061             if (P == StepPoint::pre && !this->params.detector.empty())
0062             {
0063                 // Clear detector ID for inactive threads
0064                 this->state.data.detector[track.track_slot_id()] = {};
0065             }
0066 
0067             // No more data to be written
0068             return;
0069         }
0070     }
0071 
0072     if (!this->params.detector.empty())
0073     {
0074         // Apply detector filter at beginning of step (volume in which we're
0075         // stepping)
0076         if (P == StepPoint::pre)
0077         {
0078             auto const geo = track.geometry();
0079             CELER_ASSERT(!geo.is_outside());
0080             VolumeId vol = geo.volume_id();
0081             CELER_ASSERT(vol);
0082 
0083             // Map volume ID to detector ID
0084             this->state.data.detector[track.track_slot_id()]
0085                 = this->params.detector[vol];
0086         }
0087 
0088         if (!this->state.data.detector[track.track_slot_id()])
0089         {
0090             // We're not in a sensitive detector: don't save any further data
0091             return;
0092         }
0093 
0094         if (P == StepPoint::post && this->params.nonzero_energy_deposition)
0095         {
0096             // Filter out tracks that didn't deposit energy over the step
0097             auto const pstep = track.physics_step();
0098             if (pstep.energy_deposition() == zero_quantity())
0099             {
0100                 // Clear detector ID and stop recording
0101                 this->state.data.detector[track.track_slot_id()] = {};
0102                 return;
0103             }
0104         }
0105     }
0106 
0107     this->fill(track);
0108 }
0109 
0110 //---------------------------------------------------------------------------//
0111 /*!
0112  * Gather step data on device based on the user selection.
0113  */
0114 template<StepPoint P>
0115 CELER_FUNCTION void
0116 StepGatherExecutor<P>::fill(celeritas::CoreTrackView const& track)
0117 {
0118 #define SGL_SET_IF_SELECTED(ATTR, VALUE)                          \
0119     do                                                            \
0120     {                                                             \
0121         if (this->params.selection.ATTR)                          \
0122         {                                                         \
0123             this->state.data.ATTR[track.track_slot_id()] = VALUE; \
0124         }                                                         \
0125     } while (0)
0126 
0127     {
0128         auto const sim = track.sim();
0129 
0130         SGL_SET_IF_SELECTED(points[P].time, sim.time());
0131         if constexpr (P == StepPoint::post)
0132         {
0133             SGL_SET_IF_SELECTED(event_id, sim.event_id());
0134             SGL_SET_IF_SELECTED(parent_id, sim.parent_id());
0135             SGL_SET_IF_SELECTED(track_step_count, sim.num_steps());
0136 
0137             SGL_SET_IF_SELECTED(action_id, sim.post_step_action());
0138             SGL_SET_IF_SELECTED(step_length, sim.step_length());
0139         }
0140     }
0141 
0142     {
0143         auto const geo = track.geometry();
0144 
0145         SGL_SET_IF_SELECTED(points[P].pos, geo.pos());
0146         SGL_SET_IF_SELECTED(points[P].dir, geo.dir());
0147         SGL_SET_IF_SELECTED(points[P].volume_id,
0148                             geo.is_outside() ? VolumeId{} : geo.volume_id());
0149 
0150         if (this->params.selection.points[P].volume_instance_ids)
0151         {
0152             auto dst = [this,
0153                         &vid = this->state.data.points[P].volume_instance_ids,
0154                         tid = track.track_slot_id()] {
0155                 // Destination size
0156                 size_type const size = this->params.volume_instance_depth;
0157                 size_type offset = tid.unchecked_get() * size;
0158                 auto all_ids = vid[AllItems<VolumeInstanceId>{}];
0159                 return all_ids.subspan(offset, size);
0160             }();
0161 
0162             // Fill every level from the geometry
0163             size_type depth
0164                 = geo.is_outside() ? 0 : geo.level().unchecked_get() + 1;
0165             CELER_ASSERT(depth <= dst.size());
0166             if (depth != 0)
0167             {
0168                 geo.volume_instance_id(dst.first(depth));
0169             }
0170             if constexpr (CELERITAS_DEBUG)
0171             {
0172                 for (auto level : range(depth))
0173                 {
0174                     CELER_ASSERT(dst[level]);
0175                 }
0176             }
0177 
0178             // Fill remaining levels with empty instance IDs
0179             for (auto level : range<size_type>(depth, dst.size()))
0180             {
0181                 dst[level] = {};
0182             }
0183         }
0184     }
0185 
0186     {
0187         auto const par = track.particle();
0188 
0189         if constexpr (P == StepPoint::post)
0190         {
0191             auto const pstep = track.physics_step();
0192             SGL_SET_IF_SELECTED(energy_deposition, pstep.energy_deposition());
0193             SGL_SET_IF_SELECTED(particle, par.particle_id());
0194         }
0195         SGL_SET_IF_SELECTED(points[P].energy, par.energy());
0196     }
0197 #undef SGL_SET_IF_SELECTED
0198 }
0199 
0200 //---------------------------------------------------------------------------//
0201 }  // namespace detail
0202 }  // namespace celeritas