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/detail/InitBoundaryExecutor.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include "corecel/Assert.hh"
0010 #include "corecel/Macros.hh"
0011 #include "corecel/math/ArrayOperators.hh"
0012 #include "celeritas/geo/CoreGeoTrackView.hh"
0013 #include "celeritas/optical/CoreTrackView.hh"
0014 #include "celeritas/optical/SimTrackView.hh"
0015 #include "celeritas/optical/Types.hh"
0016 #include "celeritas/optical/surface/VolumeSurfaceSelector.hh"
0017 
0018 namespace celeritas
0019 {
0020 namespace optical
0021 {
0022 namespace detail
0023 {
0024 //---------------------------------------------------------------------------//
0025 /*!
0026  * Initialize a track for crossing a boundary that has surface physics enabled.
0027  *
0028  * The track is expected to be on a boundary in the pre-crossing volume, and is
0029  * then crosses the boundary to get the post-crossing volume. If a surface
0030  * exists between these volumes then the surface ID and normal are filled in
0031  * the track's surface state data. Otherwise the track is killed at the
0032  * surface.
0033  *
0034  * \note See and update documentation in \rstref{Boundary
0035  * initialization, surface_boundary_init} .
0036  */
0037 struct InitBoundaryExecutor
0038 {
0039     // Initialize track for boundary crossing
0040     inline CELER_FUNCTION void operator()(CoreTrackView& track) const;
0041 };
0042 
0043 //---------------------------------------------------------------------------//
0044 // INLINE DEFINITIONS
0045 //---------------------------------------------------------------------------//
0046 /*!
0047  * Initialize the track for boundary crossing.
0048  */
0049 CELER_FUNCTION void InitBoundaryExecutor::operator()(CoreTrackView& track) const
0050 {
0051     CELER_EXPECT([track] {
0052         auto sim = track.sim();
0053         return sim.post_step_action()
0054                    == track.surface_physics().scalars().init_boundary_action
0055                && sim.status() == TrackStatus::alive;
0056     }());
0057 
0058     auto geo = track.geometry();
0059     CELER_EXPECT(geo.is_on_boundary());
0060 
0061     // Surface selector must be created before crossing boundary to store
0062     // pre-volume information
0063     VolumeSurfaceSelector select_surface{track.surface(),
0064                                          geo.volume_instance_id()};
0065     OptMatId pre_volume_material = track.material_record().material_id();
0066 
0067     // Move the particle across the boundary
0068     geo.cross_boundary();
0069     if (CELER_UNLIKELY(geo.failed()))
0070     {
0071         track.apply_errored();
0072         return;
0073     }
0074     if (CELER_UNLIKELY(geo.is_outside()))
0075     {
0076         track.sim().status(TrackStatus::killed);
0077         return;
0078     }
0079     OptMatId post_volume_material = track.material_record().material_id();
0080     auto surface_physics = track.surface_physics();
0081 
0082     // Find oriented surface after crossing boundary using post-volume
0083     // information
0084     auto oriented_surface
0085         = select_surface(track.surface(), geo.volume_instance_id());
0086     if (!oriented_surface)
0087     {
0088         // Use default surface properties: typically dielectric-dielectric
0089         oriented_surface.surface = surface_physics.scalars().default_surface;
0090         oriented_surface.orientation = LocalDirection::forward;
0091     }
0092 
0093     // Enforce surface normal convention, swapping normal if geometry returns
0094     // one not entering the surface
0095     Real3 global_normal = geo.normal();
0096     if (!is_entering_surface(geo.dir(), global_normal))
0097     {
0098         global_normal = -global_normal;
0099     }
0100 
0101     surface_physics = [&] {
0102         SurfacePhysicsTrackView::Initializer init;
0103         init.surface = oriented_surface.surface;
0104         init.orientation = oriented_surface.orientation;
0105         init.global_normal = global_normal;
0106         init.pre_volume_material = pre_volume_material;
0107         // Note that post-volume material may be null
0108         init.post_volume_material = post_volume_material;
0109         return init;
0110     }();
0111 
0112     CELER_ASSERT(
0113         is_entering_surface(geo.dir(), surface_physics.global_normal()));
0114 
0115     track.sim().post_step_action(
0116         surface_physics.scalars().surface_stepping_action);
0117 }
0118 
0119 //---------------------------------------------------------------------------//
0120 }  // namespace detail
0121 }  // namespace optical
0122 }  // namespace celeritas