Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-22 10:31:32

0001 //----------------------------------*-C++-*----------------------------------//
0002 // Copyright 2022-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 celeritas/user/StepData.hh
0007 //---------------------------------------------------------------------------//
0008 #pragma once
0009 
0010 #include "corecel/Macros.hh"
0011 #include "corecel/cont/EnumArray.hh"
0012 #include "corecel/cont/Range.hh"
0013 #include "corecel/data/Collection.hh"
0014 #include "corecel/data/CollectionBuilder.hh"
0015 #include "celeritas/Quantities.hh"
0016 #include "celeritas/Types.hh"
0017 #include "celeritas/Units.hh"
0018 
0019 namespace celeritas
0020 {
0021 //---------------------------------------------------------------------------//
0022 // TYPES
0023 //---------------------------------------------------------------------------//
0024 /*!
0025  * Which track properties to gather at the beginning and end of a step.
0026  *
0027  * These should all default to *false* so that this list can be extended
0028  * without adversely affecting existing interfaces.
0029  */
0030 struct StepPointSelection
0031 {
0032     bool time{false};
0033     bool pos{false};
0034     bool dir{false};
0035     bool volume_id{false};
0036     bool energy{false};
0037 
0038     //! Create StepPointSelection with all options set to true
0039     static constexpr StepPointSelection all()
0040     {
0041         return StepPointSelection{true, true, true, true, true};
0042     }
0043 
0044     //! Whether any selection is requested
0045     explicit CELER_FUNCTION operator bool() const
0046     {
0047         return time || pos || dir || volume_id || energy;
0048     }
0049 
0050     //! Combine the selection with another
0051     StepPointSelection& operator|=(StepPointSelection const& other)
0052     {
0053         this->time |= other.time;
0054         this->pos |= other.pos;
0055         this->dir |= other.dir;
0056         this->volume_id |= other.volume_id;
0057         this->energy |= other.energy;
0058         return *this;
0059     }
0060 };
0061 
0062 //---------------------------------------------------------------------------//
0063 /*!
0064  * Which track properties to gather at every step.
0065  *
0066  * These should correspond to the data items in StepStateDataImpl.
0067  *
0068  * TODO: particle -> particle_id for consistency
0069  */
0070 struct StepSelection
0071 {
0072     EnumArray<StepPoint, StepPointSelection> points;
0073 
0074     bool event_id{false};
0075     bool parent_id{false};
0076     bool track_step_count{false};
0077     bool action_id{false};
0078     bool step_length{false};
0079     bool particle{false};
0080     bool energy_deposition{false};
0081 
0082     //! Create StepSelection with all options set to true
0083     static constexpr StepSelection all()
0084     {
0085         return StepSelection{
0086             {StepPointSelection::all(), StepPointSelection::all()},
0087             true,
0088             true,
0089             true,
0090             true,
0091             true,
0092             true,
0093             true};
0094     }
0095 
0096     //! Whether any selection is requested
0097     explicit CELER_FUNCTION operator bool() const
0098     {
0099         return points[StepPoint::pre] || points[StepPoint::post] || event_id
0100                || parent_id || track_step_count || action_id || step_length
0101                || particle || energy_deposition;
0102     }
0103 
0104     //! Combine the selection with another
0105     StepSelection& operator|=(StepSelection const& other)
0106     {
0107         for (auto sp : range(StepPoint::size_))
0108         {
0109             points[sp] |= other.points[sp];
0110         }
0111 
0112         this->event_id |= other.event_id;
0113         this->parent_id |= other.parent_id;
0114         this->track_step_count |= other.track_step_count;
0115         this->action_id |= other.action_id;
0116         this->step_length |= other.step_length;
0117         this->particle |= other.particle;
0118         this->energy_deposition |= other.energy_deposition;
0119         return *this;
0120     }
0121 };
0122 
0123 //---------------------------------------------------------------------------//
0124 /*!
0125  * Shared attributes about the hits being collected.
0126  *
0127  * This will be expanded to include filters for particle type, region, etc.
0128  */
0129 template<Ownership W, MemSpace M>
0130 struct StepParamsData
0131 {
0132     //// DATA ////
0133 
0134     //! Options for gathering data at each step
0135     StepSelection selection;
0136 
0137     //! Optional mapping for volume -> sensitive detector
0138     Collection<DetectorId, W, M, VolumeId> detector;
0139 
0140     //! Filter out steps that have not deposited energy (for sensitive det)
0141     bool nonzero_energy_deposition{false};
0142 
0143     //// METHODS ////
0144 
0145     //! Whether the data is assigned
0146     explicit CELER_FUNCTION operator bool() const
0147     {
0148         return static_cast<bool>(selection);
0149     }
0150 
0151     //! Assign from another set of data
0152     template<Ownership W2, MemSpace M2>
0153     StepParamsData& operator=(StepParamsData<W2, M2> const& other)
0154     {
0155         CELER_EXPECT(other);
0156         selection = other.selection;
0157         detector = other.detector;
0158         nonzero_energy_deposition = other.nonzero_energy_deposition;
0159         return *this;
0160     }
0161 };
0162 
0163 //---------------------------------------------------------------------------//
0164 /*!
0165  * Gathered state data for beginning/end of step data for tracks in parallel.
0166  *
0167  * - Each data member corresponds exactly to a flag in \c StepPointSelection
0168  * - If the flag is disabled (no step interfaces require the data), then the
0169  *   corresponding member data will be empty.
0170  * - If a track is outside the volume (which can only happen at the end-of-step
0171  *   evaluation) the VolumeId will be "false".
0172  */
0173 template<Ownership W, MemSpace M>
0174 struct StepPointStateData
0175 {
0176     //// TYPES ////
0177 
0178     template<class T>
0179     using StateItems = celeritas::StateCollection<T, W, M>;
0180     using Energy = units::MevEnergy;
0181 
0182     // Sim
0183     StateItems<real_type> time;
0184 
0185     // Geo
0186     StateItems<Real3> pos;
0187     StateItems<Real3> dir;
0188     StateItems<VolumeId> volume_id;
0189 
0190     // Physics
0191     StateItems<Energy> energy;
0192 
0193     //// METHODS ////
0194 
0195     //! Always true since all step-point data could be disabled
0196     explicit CELER_FUNCTION operator bool() const { return true; }
0197 
0198     //! Assign from another set of states
0199     template<Ownership W2, MemSpace M2>
0200     StepPointStateData& operator=(StepPointStateData<W2, M2>& other)
0201     {
0202         CELER_EXPECT(other);
0203         time = other.time;
0204         pos = other.pos;
0205         dir = other.dir;
0206         volume_id = other.volume_id;
0207         energy = other.energy;
0208         return *this;
0209     }
0210 };
0211 
0212 //---------------------------------------------------------------------------//
0213 /*!
0214  * Gathered data for a single step for many tracks in parallel.
0215  *
0216  * - Each data member corresponds exactly to a flag in \c StepSelection .
0217  * - If the flag is disabled (no step interfaces require the data), then the
0218  *   corresponding member data will be empty.
0219  * - The track ID will be set to "false" if the track is inactive.
0220  * - If sensitive detector are specified, the \c detector field is set based
0221  *   on the pre-step geometric volume. Data members will have \b unspecified
0222  *   values if the detector ID is "false" (i.e. no information is being
0223  *   collected). The detector ID for inactive threads is always "false".
0224  */
0225 template<Ownership W, MemSpace M>
0226 struct StepStateDataImpl
0227 {
0228     //// TYPES ////
0229 
0230     using StepPointData = StepPointStateData<W, M>;
0231     template<class T>
0232     using StateItems = celeritas::StateCollection<T, W, M>;
0233     using Energy = units::MevEnergy;
0234 
0235     //// DATA ////
0236 
0237     // Pre- and post-step data
0238     EnumArray<StepPoint, StepPointData> points;
0239 
0240     //! Track ID is always assigned (but will be false for inactive tracks)
0241     StateItems<TrackId> track_id;
0242 
0243     //! Detector ID is non-empty if params.detector is nonempty
0244     StateItems<DetectorId> detector;
0245 
0246     // Sim
0247     StateItems<EventId> event_id;
0248     StateItems<TrackId> parent_id;
0249     StateItems<ActionId> action_id;
0250     StateItems<size_type> track_step_count;
0251     StateItems<real_type> step_length;
0252 
0253     // Physics
0254     StateItems<ParticleId> particle;
0255     StateItems<Energy> energy_deposition;
0256 
0257     //// METHODS ////
0258 
0259     //! True if constructed and correctly sized
0260     explicit CELER_FUNCTION operator bool() const
0261     {
0262         auto right_sized = [this](auto const& t) {
0263             return (t.size() == this->size()) || t.empty();
0264         };
0265 
0266         return !track_id.empty() && right_sized(detector)
0267                && right_sized(event_id) && right_sized(parent_id)
0268                && right_sized(track_step_count) && right_sized(action_id)
0269                && right_sized(step_length) && right_sized(particle)
0270                && right_sized(energy_deposition);
0271     }
0272 
0273     //! State size
0274     CELER_FUNCTION TrackSlotId::size_type size() const
0275     {
0276         return track_id.size();
0277     }
0278 
0279     //! Assign from another set of states
0280     template<Ownership W2, MemSpace M2>
0281     StepStateDataImpl& operator=(StepStateDataImpl<W2, M2>& other)
0282     {
0283         // The extra storage used to gather the step data is only required on
0284         // the device
0285         CELER_EXPECT(other || (M == MemSpace::host && other.size() == 0));
0286 
0287         for (auto sp : range(StepPoint::size_))
0288         {
0289             points[sp] = other.points[sp];
0290         }
0291 
0292         track_id = other.track_id;
0293         parent_id = other.parent_id;
0294         detector = other.detector;
0295         event_id = other.event_id;
0296         track_step_count = other.track_step_count;
0297         action_id = other.action_id;
0298         step_length = other.step_length;
0299         particle = other.particle;
0300         energy_deposition = other.energy_deposition;
0301         return *this;
0302     }
0303 };
0304 
0305 //---------------------------------------------------------------------------//
0306 /*!
0307  * Gathered data and persistent scratch space for gathering and copying data.
0308  *
0309  * Extra storage \c scratch and \c valid_id is needed to efficiently gather and
0310  * copy the step data on the device but will not be allocated on the host.
0311  */
0312 template<Ownership W, MemSpace M>
0313 struct StepStateData
0314 {
0315     //// TYPES ////
0316 
0317     using StepDataImpl = StepStateDataImpl<W, M>;
0318     template<class T>
0319     using StateItems = celeritas::StateCollection<T, W, M>;
0320 
0321     //// DATA ////
0322 
0323     //! Gathered data for a single step
0324     StepDataImpl data;
0325 
0326     //! Scratch space for gathering the data on device based on track validity
0327     StepDataImpl scratch;
0328 
0329     //! Thread IDs of active tracks that are in a detector
0330     StateItems<size_type> valid_id;
0331 
0332     //! Unique identifier for "thread-local" data.
0333     StreamId stream_id;
0334 
0335     //// METHODS ////
0336 
0337     //! True if constructed and correctly sized
0338     explicit CELER_FUNCTION operator bool() const
0339     {
0340         auto right_sized = [this](auto const& t) {
0341             return (t.size() == this->size())
0342                    || (t.size() == 0 && M == MemSpace::host);
0343         };
0344 
0345         return data.size() > 0 && right_sized(scratch) && right_sized(valid_id)
0346                && stream_id;
0347     }
0348 
0349     //! State size
0350     CELER_FUNCTION TrackSlotId::size_type size() const { return data.size(); }
0351 
0352     //! Assign from another set of states
0353     template<Ownership W2, MemSpace M2>
0354     StepStateData& operator=(StepStateData<W2, M2>& other)
0355     {
0356         CELER_EXPECT(other);
0357 
0358         data = other.data;
0359         scratch = other.scratch;
0360         valid_id = other.valid_id;
0361         stream_id = other.stream_id;
0362         return *this;
0363     }
0364 };
0365 
0366 //---------------------------------------------------------------------------//
0367 // HELPER FUNCTIONS
0368 //---------------------------------------------------------------------------//
0369 /*!
0370  * Resize a state point.
0371  */
0372 template<MemSpace M>
0373 inline void resize(StepPointStateData<Ownership::value, M>* state,
0374                    StepPointSelection selection,
0375                    size_type size)
0376 {
0377     CELER_EXPECT(size > 0);
0378 #define SD_RESIZE_IF_SELECTED(ATTR)     \
0379     do                                  \
0380     {                                   \
0381         if (selection.ATTR)             \
0382         {                               \
0383             resize(&state->ATTR, size); \
0384         }                               \
0385     } while (0)
0386 
0387     SD_RESIZE_IF_SELECTED(time);
0388     SD_RESIZE_IF_SELECTED(pos);
0389     SD_RESIZE_IF_SELECTED(dir);
0390     SD_RESIZE_IF_SELECTED(volume_id);
0391     SD_RESIZE_IF_SELECTED(energy);
0392 
0393 #undef SD_RESIZE_IF_SELECTED
0394 }
0395 
0396 //---------------------------------------------------------------------------//
0397 /*!
0398  * Resize the step data.
0399  */
0400 template<MemSpace M>
0401 inline void resize(StepStateDataImpl<Ownership::value, M>* state,
0402                    HostCRef<StepParamsData> const& params,
0403                    size_type size)
0404 {
0405     CELER_EXPECT(state->size() == 0);
0406     CELER_EXPECT(size > 0);
0407 
0408     for (auto sp : range(StepPoint::size_))
0409     {
0410         resize(&state->points[sp], params.selection.points[sp], size);
0411     }
0412 
0413 #define SD_RESIZE_IF_SELECTED(ATTR)     \
0414     do                                  \
0415     {                                   \
0416         if (params.selection.ATTR)      \
0417         {                               \
0418             resize(&state->ATTR, size); \
0419         }                               \
0420     } while (0)
0421 
0422     resize(&state->track_id, size);
0423     if (!params.detector.empty())
0424     {
0425         resize(&state->detector, size);
0426     }
0427 
0428     SD_RESIZE_IF_SELECTED(event_id);
0429     SD_RESIZE_IF_SELECTED(parent_id);
0430     SD_RESIZE_IF_SELECTED(track_step_count);
0431     SD_RESIZE_IF_SELECTED(step_length);
0432     SD_RESIZE_IF_SELECTED(action_id);
0433     SD_RESIZE_IF_SELECTED(particle);
0434     SD_RESIZE_IF_SELECTED(energy_deposition);
0435 }
0436 
0437 //---------------------------------------------------------------------------//
0438 /*!
0439  * Resize the state.
0440  */
0441 template<MemSpace M>
0442 inline void resize(StepStateData<Ownership::value, M>* state,
0443                    HostCRef<StepParamsData> const& params,
0444                    StreamId stream_id,
0445                    size_type size)
0446 {
0447     CELER_EXPECT(state->size() == 0);
0448     CELER_EXPECT(size > 0);
0449 
0450     state->stream_id = stream_id;
0451 
0452     resize(&state->data, params, size);
0453 
0454     if constexpr (M == MemSpace::device)
0455     {
0456         // Allocate extra space on device for gathering step data
0457         resize(&state->scratch, params, size);
0458         resize(&state->valid_id, size);
0459     }
0460 }
0461 
0462 //---------------------------------------------------------------------------//
0463 }  // namespace celeritas