Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-07 10:11:39

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/surface/model/ReflectionFormSampler.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include "corecel/random/distribution/Selector.hh"
0010 
0011 #include "DielectricInteractionData.hh"
0012 #include "ReflectionFormCalculator.hh"
0013 
0014 namespace celeritas
0015 {
0016 namespace optical
0017 {
0018 //---------------------------------------------------------------------------//
0019 /*!
0020  * Calculate probability for each reflection mode from UNIFIED model grids.
0021  *
0022  * \todo Rename ReflectionModeCalculator
0023  * \todo If this ends up being expensive, we could use a unified grid (union of
0024  * all points on sub-grids) to do a single lookup and interpolate PDFs more
0025  * effectively.
0026  */
0027 class ReflectionModeSampler
0028 {
0029   public:
0030     //!@{
0031     //! \name Type aliases
0032     using DataRef = NativeCRef<UnifiedReflectionData>;
0033     using Energy = units::MevEnergy;
0034     //!@}
0035 
0036   public:
0037     // Construct from data, surface, and energy
0038     explicit inline CELER_FUNCTION ReflectionModeSampler(
0039         DataRef const&, SubModelId, Energy);
0040 
0041     // Calculate probability for a specific reflection mode
0042     inline CELER_FUNCTION real_type operator()(ReflectionMode) const;
0043 
0044   private:
0045     DataRef const& data_;
0046     SubModelId surface_;
0047     Energy energy_;
0048 };
0049 
0050 //---------------------------------------------------------------------------//
0051 /*!
0052  * Sample a reflection result based on UNIFIED model grid probabilities.
0053  */
0054 class ReflectionFormSampler
0055 {
0056   public:
0057     // Construct from a mode sampler and a reflection calculator
0058     inline CELER_FUNCTION ReflectionFormSampler(
0059         ReflectionModeSampler sample_mode,
0060         ReflectionFormCalculator const& calc_reflection);
0061 
0062     // Sample a surface interaction
0063     template<class Engine>
0064     inline CELER_FUNCTION SurfaceInteraction operator()(Engine&) const;
0065 
0066   private:
0067     Selector<ReflectionModeSampler, ReflectionMode> sample_mode_;
0068     ReflectionFormCalculator const& calc_reflection_;
0069 };
0070 
0071 //---------------------------------------------------------------------------//
0072 // INLINE DEFINITIONS
0073 //---------------------------------------------------------------------------//
0074 /*!
0075  * Construct from data, surface, and energy.
0076  */
0077 CELER_FUNCTION ReflectionModeSampler::ReflectionModeSampler(
0078     DataRef const& data, SubModelId surface, Energy energy)
0079     : data_(data), surface_(surface), energy_(energy)
0080 {
0081     CELER_EXPECT(surface_ < data_.size());
0082 }
0083 
0084 //---------------------------------------------------------------------------//
0085 /*!
0086  * Calculate probability for the given reflection mode.
0087  *
0088  * Only the specular spike, specular lobe, and back-scattering probabilities
0089  * are defined as grids in the data. The diffuse Lambertian mode is the
0090  * remaining probability.
0091  */
0092 CELER_FUNCTION real_type ReflectionModeSampler::operator()(
0093     ReflectionMode mode) const
0094 {
0095     NonuniformGridCalculator calc{data_.reflection_grids[mode][surface_],
0096                                   data_.reals};
0097     real_type result = calc(value_as<Energy>(energy_));
0098     CELER_ENSURE(result >= 0 && result <= 1);
0099     return result;
0100 }
0101 
0102 //---------------------------------------------------------------------------//
0103 /*!
0104  * Construct from a mode sampler and reflection calculator.
0105  */
0106 CELER_FUNCTION ReflectionFormSampler::ReflectionFormSampler(
0107     ReflectionModeSampler sample_mode,
0108     ReflectionFormCalculator const& calc_reflection)
0109     : sample_mode_{make_unnormalized_selector(
0110           std::move(sample_mode), ReflectionMode::size_, real_type{1})}
0111     , calc_reflection_(calc_reflection)
0112 {
0113 }
0114 
0115 //---------------------------------------------------------------------------//
0116 /*!
0117  * Sample a surface interaction.
0118  */
0119 template<class Engine>
0120 inline CELER_FUNCTION SurfaceInteraction ReflectionFormSampler::operator()(
0121     Engine& rng) const
0122 {
0123     switch (sample_mode_(rng))
0124     {
0125         case ReflectionMode::specular_spike:
0126             return calc_reflection_.calc_specular_spike();
0127         case ReflectionMode::specular_lobe:
0128             return calc_reflection_.calc_specular_lobe();
0129         case ReflectionMode::backscatter:
0130             return calc_reflection_.calc_backscatter();
0131         case ReflectionMode::diffuse_lobe:
0132             // The other probabilities are allowed to sum to less than unity:
0133             // the remainder is diffuse
0134             return calc_reflection_.sample_lambertian_reflection(rng);
0135         default:
0136             CELER_ASSERT_UNREACHABLE();
0137     }
0138 }
0139 //---------------------------------------------------------------------------//
0140 }  // namespace optical
0141 }  // namespace celeritas