File indexing completed on 2025-09-16 09:03:18
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include "corecel/Assert.hh"
0010 #include "corecel/cont/Array.hh"
0011 #include "corecel/math/Algorithms.hh"
0012 #include "corecel/math/ArrayUtils.hh"
0013 #include "corecel/math/NumericLimits.hh"
0014
0015 #include "Types.hh"
0016
0017 namespace celeritas
0018 {
0019 namespace detail
0020 {
0021
0022
0023 struct CalcSense
0024 {
0025 Real3 const& pos;
0026
0027 template<class S>
0028 CELER_FUNCTION SignedSense operator()(S const& surf)
0029 {
0030 return surf.calc_sense(this->pos);
0031 }
0032 };
0033
0034
0035
0036 struct NumIntersections
0037 {
0038 template<class ST>
0039 CELER_CONSTEXPR_FUNCTION size_type operator()(ST) const noexcept
0040 {
0041 using S = typename ST::type;
0042 return typename S::Intersections{}.size();
0043 }
0044 };
0045
0046
0047
0048 struct CalcNormal
0049 {
0050 Real3 const& pos;
0051
0052 template<class S>
0053 CELER_FUNCTION Real3 operator()(S const& surf)
0054 {
0055 return surf.calc_normal(this->pos);
0056 }
0057 };
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067 struct CalcSafetyDistance
0068 {
0069 Real3 const& pos;
0070
0071
0072 template<class S>
0073 CELER_FUNCTION real_type operator()(S const& surf)
0074 {
0075 if (!S::simple_safety())
0076 {
0077
0078
0079 return 0;
0080 }
0081
0082
0083 Real3 dir = surf.calc_normal(this->pos);
0084 if (CELER_UNLIKELY(std::isnan(dir[0])))
0085 {
0086
0087
0088 return numeric_limits<real_type>::infinity();
0089 }
0090 CELER_ASSERT(is_soft_unit_vector(dir));
0091
0092 auto sense = surf.calc_sense(this->pos);
0093
0094
0095 if (sense == SignedSense::outside)
0096 {
0097 for (real_type& d : dir)
0098 {
0099 d *= -1;
0100 }
0101 }
0102 else if (sense == SignedSense::on)
0103 {
0104 return 0;
0105 }
0106
0107
0108 auto intersect
0109 = surf.calc_intersections(this->pos, dir, SurfaceState::off);
0110 return *celeritas::min_element(intersect.begin(), intersect.end());
0111 }
0112 };
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123 template<class F>
0124 class CalcIntersections
0125 {
0126 public:
0127
0128 CELER_FUNCTION CalcIntersections(F&& is_valid_isect,
0129 Real3 const& pos,
0130 Real3 const& dir,
0131 FaceId on_face,
0132 bool is_simple,
0133 TempNextFace const& next_face)
0134 : is_valid_isect_(celeritas::forward<F>(is_valid_isect))
0135 , pos_(pos)
0136 , dir_(dir)
0137 , on_face_idx_(on_face.unchecked_get())
0138 , fill_isect_(!is_simple)
0139 , face_(next_face.face)
0140 , distance_(next_face.distance)
0141 , isect_(next_face.isect)
0142 {
0143 CELER_EXPECT(face_ && distance_);
0144 }
0145
0146
0147 template<class S>
0148 CELER_FUNCTION void operator()(S const& surf)
0149 {
0150 auto on_surface = (on_face_idx_ == face_idx_) ? SurfaceState::on
0151 : SurfaceState::off;
0152 if constexpr (typename S::Intersections{}.size() == 1)
0153 {
0154 if (on_surface == SurfaceState::on)
0155 {
0156
0157 ++face_idx_;
0158 return;
0159 }
0160 }
0161
0162
0163 auto all_dist = surf.calc_intersections(pos_, dir_, on_surface);
0164
0165
0166 for (real_type dist : all_dist)
0167 {
0168 CELER_ASSERT(dist > 0);
0169 if (is_valid_isect_(dist))
0170 {
0171
0172 face_[isect_idx_] = FaceId{face_idx_};
0173 distance_[isect_idx_] = dist;
0174 if (fill_isect_)
0175 {
0176 isect_[isect_idx_] = isect_idx_;
0177 }
0178 ++isect_idx_;
0179 }
0180 }
0181
0182 ++face_idx_;
0183 }
0184
0185 CELER_FUNCTION size_type face_idx() const { return face_idx_; }
0186 CELER_FUNCTION size_type isect_idx() const { return isect_idx_; }
0187
0188 private:
0189
0190
0191 F is_valid_isect_;
0192 Real3 const& pos_;
0193 Real3 const& dir_;
0194 size_type const on_face_idx_;
0195 bool const fill_isect_;
0196 FaceId* const face_;
0197 real_type* const distance_;
0198 size_type* const isect_;
0199 size_type face_idx_{0};
0200 size_type isect_idx_{0};
0201 };
0202
0203 template<class F, class... Args>
0204 CELER_FUNCTION CalcIntersections(F&&, Args&&... args) -> CalcIntersections<F>;
0205
0206
0207 }
0208 }