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