Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-01-01 09:40:25

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