IPPL API Reference
Independent Parallel Particle Layer C++ API
Loading...
Searching...
No Matches
GridPathSegmenter.hpp
1#include <array>
2#include <cmath>
3#include <type_traits>
4
5namespace ippl {
6
7// Helper to pass loop indices as compile-time constants to f.
8template<int I, int End, class F>
9KOKKOS_INLINE_FUNCTION
10constexpr void static_for(F&& f) {
11 if constexpr (I < End) {
12 f(std::integral_constant<int, I>{});
13 static_for<I+1, End>(std::forward<F>(f));
14 }
15}
16
17//Utility function to sort crossing times, so path segments are ordered correctly. Without sorting, they would be ordered by which dimension is crossed
18template<typename T>
19KOKKOS_INLINE_FUNCTION
20void sort2(T& a, T& b) { if (a > b) { T t=a; a=b; b=t; } }
21
22//Same as above for the case of 3 crossings
23template<typename T>
24KOKKOS_INLINE_FUNCTION
25void sort3(T& a, T& b, T& c) { sort2(a,b); sort2(b,c); sort2(a,b); }
26
27//Linear interpolation helper to convert the crossing times into segment endpoints.
28template<unsigned Dim, typename T>
29KOKKOS_INLINE_FUNCTION
30Vector<T,Dim> lerp_point(const Vector<T,Dim>& A,
31 const Vector<T,Dim>& B, T t) {
32 Vector<T,Dim> out{};
33 for (unsigned a=0; a<Dim; ++a) out[a] = A[a] + (B[a]-A[a]) * t;
34 return out;
35}
36
37// ---------- per-axis cut times (for DefaultCellCrossingRule) ----------
38template<unsigned Dim, typename T>
39struct CutTimes { Kokkos::Array<T,Dim> t; };
40
41template<unsigned Dim, typename T>
42KOKKOS_INLINE_FUNCTION
43CutTimes<Dim,T> compute_axis_cuts_default(
44 const Vector<T,Dim>& A,
45 const Vector<T,Dim>& B,
46 const Vector<T,Dim>& origin,
47 const Vector<T,Dim>& h)
48{
49 CutTimes<Dim,T> cuts;
50 for (unsigned a=0; a<Dim; ++a) cuts.t[a] = (T)2; // initialize to 2: value > 1 means no crossing
51
52 const T eps1 = (T)1e-12, one = (T)1;
53
54 auto axis_cut = [&](auto Ax) {
55 constexpr int a = decltype(Ax)::value;
56 const T dist = B[a] - A[a];
57 const T eps = eps1 * h[a];
58 if (Kokkos::fabs(dist) <= eps) return; // no motion → no crossing
59
60 const T nA = (A[a] - origin[a]) / h[a]; // in cell units
61 // nearest plane index in direction toward B; bias off-plane a hair
62 const T k = (dist > 0) ? Kokkos::ceil(nA - eps1) : Kokkos::floor(nA + eps1);
63 const T pa = origin[a] + k * h[a];
64 // Parametric crossing time; only store if strictly between A and B.
65 const T t = (pa - A[a]) / dist;
66 if (t > eps1 && t < one - eps1) cuts.t[a] = t;
67 };
68
69 //Loop over axes 0..Dim-1 at compile time so each index is a compile-time constant.
70 static_for<0,Dim>(axis_cut);
71 return cuts;
72}
73
74// ---------- endpoints builder: [0, t_sorted..., 1] (keeps duplicates) ----------
75template<unsigned Dim, typename T>
76KOKKOS_INLINE_FUNCTION
77void make_endpoints_fixed(const CutTimes<Dim,T>& cuts,
78 Kokkos::Array<T,Dim+2>& Tcuts /*out*/)
79{
80 T t0 = cuts.t[0];
81 T t1 = (Dim>=2) ? cuts.t[1] : (T)2;
82 T t2 = (Dim==3) ? cuts.t[2] : (T)2;
83
84 if constexpr (Dim==2) {
85 sort2(t0, t1);
86 } else { // Dim==3
87 sort3(t0, t1, t2);
88 }
89
90 const T one = (T)1;
91 auto clamp_or_one = [&](T v)->T { return (v >= one) ? one : v; };
92
93 Tcuts[0] = (T)0;
94 Tcuts[1] = clamp_or_one(t0);
95 if constexpr (Dim>=2) Tcuts[2] = clamp_or_one(t1);
96 if constexpr (Dim==3) Tcuts[3] = clamp_or_one(t2);
97 Tcuts[Dim+1] = one;
98}
99
100// ---------------------------------------------------------------------------------
101// DefaultCellCrossingRule specialization
102// ---------------------------------------------------------------------------------
103
104template<unsigned Dim, typename T, typename Rule>
105KOKKOS_INLINE_FUNCTION
106Kokkos::Array<Segment<Dim,T>, Dim+1>
107GridPathSegmenter<Dim,T,Rule>::split(
108 const Vector<T,Dim>& A,
109 const Vector<T,Dim>& B,
110 const Vector<T,Dim>& origin,
111 const Vector<T,Dim>& h)
112{
113 const auto cuts = compute_axis_cuts_default<Dim,T>(A,B,origin,h);
114
115 Kokkos::Array<T,Dim+2> Tcuts{};
116 make_endpoints_fixed<Dim,T>(cuts, Tcuts);
117
118 Kokkos::Array<Segment<Dim,T>, Dim+1> segs{};
119 for (unsigned i = 0; i < Dim + 1; ++i) {
120 const T ta = Tcuts[i];
121 const T tb = Tcuts[i+1];
122 segs[i].p0 = lerp_point<Dim,T>(A,B,ta);
123 segs[i].p1 = lerp_point<Dim,T>(A,B,tb);
124 }
125 return segs;
126}
127
128} // namespace ippl
Definition Vector.h:23
Definition Archive.h:20
Definition GridPathSegmenter.hpp:39