Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-01-07 10:01:43

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/optical/gen/ScintillationData.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include "corecel/Macros.hh"
0010 #include "corecel/Types.hh"
0011 #include "corecel/data/Collection.hh"
0012 #include "corecel/grid/NonuniformGridData.hh"
0013 #include "celeritas/Types.hh"
0014 
0015 #include "../Types.hh"
0016 
0017 namespace celeritas
0018 {
0019 //---------------------------------------------------------------------------//
0020 /*!
0021  * Parameterized scintillation properties.
0022  *
0023  * This component represents one type of scintillation emissions, such as
0024  * prompt/fast, intermediate, or slow. It can be specific to a material or
0025  * depend on the incident particle type.
0026  */
0027 struct ScintRecord
0028 {
0029     real_type lambda_mean{};  //!< Mean wavelength
0030     real_type lambda_sigma{};  //!< Standard deviation of wavelength
0031     real_type rise_time{};  //!< Rise time
0032     real_type fall_time{};  //!< Decay time
0033 
0034     //! Whether all data are assigned and valid
0035     explicit CELER_FUNCTION operator bool() const
0036     {
0037         return lambda_mean > 0 && lambda_sigma > 0 && rise_time >= 0
0038                && fall_time > 0;
0039     }
0040 };
0041 
0042 //---------------------------------------------------------------------------//
0043 /*!
0044  * Material-dependent scintillation spectrum.
0045  *
0046  * - \c yield_per_energy is the characteristic light yield of the material in
0047  *   [1/MeV] units. The total light yield per step is the characteristic light
0048  *   yield multiplied by the energy deposition, which results in a (unitless)
0049  *   number of photons.
0050  * - \c yield_pdf is the probability of choosing from a given component.
0051  * - \c components stores the different scintillation components
0052  *   (fast/slow/etc) for this material.
0053  */
0054 struct MatScintSpectrum
0055 {
0056     real_type yield_per_energy{};  //!< [1/MeV]
0057     ItemRange<real_type> yield_pdf;
0058     ItemRange<ScintRecord> components;
0059 
0060     //! Whether all data are assigned and valid
0061     explicit CELER_FUNCTION operator bool() const
0062     {
0063         return yield_per_energy > 0 && !yield_pdf.empty()
0064                && yield_pdf.size() == components.size();
0065     }
0066 };
0067 
0068 //---------------------------------------------------------------------------//
0069 /*!
0070  * Particle- and material-dependent scintillation spectrum.
0071  *
0072  * - \c yield_vector is the characteristic light yield for different energies.
0073  * - \c yield_pdf is the probability of choosing from a given component.
0074  * - \c components stores the fast/slow/etc scintillation components for this
0075  * particle type.
0076  */
0077 struct ParScintSpectrum
0078 {
0079     NonuniformGridRecord yield_per_energy;  //! [MeV] -> [1/MeV]
0080     ItemRange<real_type> yield_pdf;
0081     ItemRange<ScintRecord> components;
0082 
0083     //! Whether all data are assigned and valid
0084     explicit CELER_FUNCTION operator bool() const
0085     {
0086         return yield_per_energy && !yield_pdf.empty()
0087                && yield_pdf.size() == components.size();
0088     }
0089 };
0090 
0091 //---------------------------------------------------------------------------//
0092 /*!
0093  * Data characterizing the scintillation spectrum for all particles and
0094  * materials.
0095  *
0096  * Sampling using material-only data or particle- and material-dependent data
0097  * are mutually exclusive. Therefore, either \c materials or \c particles are
0098  * loaded at the beginning of the simulation, but *never* both at the same
0099  * time. The \c scintillation_by_particle() function can be used to check that.
0100  *
0101  * - \c pid_to_scintpid maps a \c ParticleId to a \c ScintParticleId .
0102  * - \c resolution_scale is indexed by \c OptMatId .
0103  * - \c materials stores particle-independent scintillation data.
0104  * - \c particles stores the scintillation spectrum for each particle type and
0105  *   material. It has size \c num_particles * \c num_materials and is indexed
0106  *   by \c ParScintSpectrumId , which can be calculated from a \c OptMatId and
0107  *   \c ScintParticleId using the \c spectrum_index() helper method.
0108  */
0109 template<Ownership W, MemSpace M>
0110 struct ScintillationData
0111 {
0112     template<class T>
0113     using Items = Collection<T, W, M>;
0114     template<class T>
0115     using OptMatItems = Collection<T, W, M, OptMatId>;
0116     template<class T>
0117     using ParticleItems = Collection<T, W, M, ParticleId>;
0118     template<class T>
0119     using ParScintSpectrumItems = Collection<T, W, M, ParScintSpectrumId>;
0120 
0121     //// MEMBER DATA ////
0122 
0123     //! Number of scintillation particles, used by this->spectrum_index
0124     size_type num_scint_particles{};
0125 
0126     //! Resolution scale for each material [OptMatId]
0127     OptMatItems<real_type> resolution_scale;
0128     //! Material-dependent scintillation spectrum data [OptMatId]
0129     OptMatItems<MatScintSpectrum> materials;
0130 
0131     //! Index between \c ScintParticleId and \c ParticleId
0132     ParticleItems<ScintParticleId> pid_to_scintpid;
0133     //! Particle/material scintillation spectrum data [ParScintSpectrumId]
0134     ParScintSpectrumItems<ParScintSpectrum> particles;
0135 
0136     //! Backend storage for real values
0137     Items<real_type> reals;
0138     //! Backend storage for scintillation components
0139     Items<ScintRecord> scint_records;
0140 
0141     //// MEMBER FUNCTIONS ////
0142 
0143     //! Whether all data are assigned and valid
0144     explicit CELER_FUNCTION operator bool() const
0145     {
0146         return !resolution_scale.empty()
0147                && (materials.empty() != particles.empty())
0148                && (!pid_to_scintpid.empty() == !particles.empty())
0149                && (!pid_to_scintpid.empty() == (num_scint_particles > 0));
0150     }
0151 
0152     //! Whether sampling must happen by particle type
0153     CELER_FUNCTION bool scintillation_by_particle() const
0154     {
0155         return !particles.empty();
0156     }
0157 
0158     //! Retrieve spectrum index given optical particle and material ids
0159     ParScintSpectrumId spectrum_index(ScintParticleId pid, OptMatId mid) const
0160     {
0161         // Resolution scale exists independent of material-only data and it's
0162         // indexed by optical material id
0163         CELER_EXPECT(pid < num_scint_particles);
0164         CELER_EXPECT(mid < resolution_scale.size());
0165         return ParScintSpectrumId{resolution_scale.size() * pid.get()
0166                                   + mid.get()};
0167     }
0168 
0169     //! Assign from another set of data
0170     template<Ownership W2, MemSpace M2>
0171     ScintillationData& operator=(ScintillationData<W2, M2> const& other)
0172     {
0173         CELER_EXPECT(other);
0174         resolution_scale = other.resolution_scale;
0175         materials = other.materials;
0176         pid_to_scintpid = other.pid_to_scintpid;
0177         num_scint_particles = other.num_scint_particles;
0178         particles = other.particles;
0179         reals = other.reals;
0180         scint_records = other.scint_records;
0181         return *this;
0182     }
0183 };
0184 
0185 //---------------------------------------------------------------------------//
0186 }  // namespace celeritas