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/DielectricInteractor.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include "corecel/random/distribution/BernoulliDistribution.hh"
0010 #include "celeritas/optical/CoreTrackView.hh"
0011 
0012 #include "FresnelCalculator.hh"
0013 #include "ReflectionFormSampler.hh"
0014 
0015 namespace celeritas
0016 {
0017 namespace optical
0018 {
0019 //---------------------------------------------------------------------------//
0020 /*!
0021  * Sample optical interactions for dielectric-dielectric and dielectric-metal
0022  * interfaces.
0023  *
0024  * For both interfaces, the reflectivity is first calculated from Fresnel
0025  * equations with the \c FresnelCalculator and sampled to determine if the
0026  * photon will reflect or refract. If it reflects, then the UNIFIED model is
0027  * used to handle the different forms of reflection via \c
0028  * ReflectionFormSampler. If it refracts, then dielectric-dielectric interfaces
0029  * will use Snell's law to determine the refracted wave direction and
0030  * polarization. For dielectric-metal interfaces, refracted waves are just
0031  * absorbed.
0032  *
0033  * The result is used by \c SurfaceInteractionApplier to update the track.
0034  */
0035 class DielectricInteractor
0036 {
0037   public:
0038     struct Executor
0039     {
0040         NativeCRef<DielectricData> dielectric_data;
0041         NativeCRef<UnifiedReflectionData> unified_data;
0042 
0043         // Build and sample interactor for a track
0044         inline CELER_FUNCTION SurfaceInteraction operator()(
0045             CoreTrackView const&) const;
0046     };
0047 
0048   public:
0049     // Construct interactor from track data
0050     inline CELER_FUNCTION DielectricInteractor(
0051         ParticleTrackView const& particle,
0052         Real3 const& inc_direction,
0053         SurfacePhysicsTrackView const& surface_physics,
0054         MaterialView const& pre_material,
0055         MaterialView const& post_material,
0056         ReflectionModeSampler reflection_calc,
0057         DielectricInterface dielectric_interface);
0058 
0059     // Sample the dielectric interaction
0060     template<class Engine>
0061     inline CELER_FUNCTION SurfaceInteraction operator()(Engine&) const;
0062 
0063   private:
0064     FresnelCalculator fresnel_;
0065     Real3 const& inc_direction_;
0066     ParticleTrackView const& inc_photon_;
0067     SurfacePhysicsTrackView const& surface_phys_;
0068     ReflectionModeSampler reflection_calc_;
0069     DielectricInterface dielectric_interface_;
0070 };
0071 
0072 //---------------------------------------------------------------------------//
0073 // INLINE DEFINITIONS
0074 //---------------------------------------------------------------------------//
0075 /*!
0076  * Create an interactor and sample it for the given track.
0077  */
0078 CELER_FUNCTION SurfaceInteraction DielectricInteractor::Executor::operator()(
0079     CoreTrackView const& track) const
0080 {
0081     auto s_phys = track.surface_physics();
0082 
0083     // Can't do analytic interaction if there's no post-volume optical material
0084     if (!s_phys.next_material())
0085     {
0086         return SurfaceInteraction::from_absorption();
0087     }
0088 
0089     // No interaction if optical materials are identical
0090     if (s_phys.material() == s_phys.next_material())
0091     {
0092         return SurfaceInteraction::from_transmission();
0093     }
0094 
0095     auto rng = track.rng();
0096     auto sub_model_id
0097         = s_phys.interface(SurfacePhysicsOrder::interaction).internal_surface_id();
0098     CELER_ASSERT(sub_model_id < dielectric_data.interface.size());
0099 
0100     return DielectricInteractor{
0101         track.particle(),
0102         track.geometry().dir(),
0103         s_phys,
0104         track.material_record(s_phys.material()),
0105         track.material_record(s_phys.next_material()),
0106         ReflectionModeSampler{
0107             unified_data, sub_model_id, track.particle().energy()},
0108         dielectric_data.interface[sub_model_id]}(rng);
0109 }
0110 
0111 //---------------------------------------------------------------------------//
0112 /*!
0113  * Construct an interactor from track views.
0114  */
0115 CELER_FUNCTION DielectricInteractor::DielectricInteractor(
0116     ParticleTrackView const& particle,
0117     Real3 const& inc_direction,
0118     SurfacePhysicsTrackView const& surface_physics,
0119     MaterialView const& pre_material,
0120     MaterialView const& post_material,
0121     ReflectionModeSampler reflection_calc,
0122     DielectricInterface dielectric_interface)
0123     : fresnel_(inc_direction,
0124                particle,
0125                surface_physics.facet_normal(),
0126                pre_material,
0127                post_material)
0128     , inc_direction_(inc_direction)
0129     , inc_photon_(particle)
0130     , surface_phys_(surface_physics)
0131     , reflection_calc_(reflection_calc)
0132     , dielectric_interface_(dielectric_interface)
0133 {
0134 }
0135 
0136 //---------------------------------------------------------------------------//
0137 /*!
0138  * Sample the dielectric interaction.
0139  */
0140 template<class Engine>
0141 CELER_FUNCTION SurfaceInteraction DielectricInteractor::operator()(
0142     Engine& rng) const
0143 {
0144     if (BernoulliDistribution{fresnel_.calc_reflectivity()}(rng))
0145     {
0146         // Reflection
0147         return ReflectionFormSampler{
0148             reflection_calc_,
0149             ReflectionFormCalculator{
0150                 inc_direction_, inc_photon_, surface_phys_}}(rng);
0151     }
0152     else
0153     {
0154         // Refraction
0155         switch (dielectric_interface_)
0156         {
0157             case DielectricInterface::metal:
0158                 return SurfaceInteraction::from_absorption();
0159             case DielectricInterface::dielectric:
0160                 return fresnel_.refracted_interaction();
0161             default:
0162                 CELER_ASSERT_UNREACHABLE();
0163         }
0164     }
0165 }
0166 
0167 //---------------------------------------------------------------------------//
0168 }  // namespace optical
0169 }  // namespace celeritas