Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/celeritas/user/StepData.hh was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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