/home/runner/work/DiFfRG/DiFfRG/DiFfRG/include/DiFfRG/discretization/coordinates/coordinates.hh Source File#

DiFfRG: /home/runner/work/DiFfRG/DiFfRG/DiFfRG/include/DiFfRG/discretization/coordinates/coordinates.hh Source File
DiFfRG
Discretization Framework for functional Renormalization Group flows
coordinates.hh
Go to the documentation of this file.
1#pragma once
2
3// standard library
4#include <cmath>
5#include <cstddef>
6#include <cstdio>
7#include <cstdlib>
8#include <limits>
9#include <stdexcept>
10#include <string>
11#include <tuple>
12#include <type_traits>
13#include <utility>
14#include <vector>
15
16// DiFfRG
19
20namespace DiFfRG
21{
28 template <typename T>
29 concept is_coordinates = requires(T t) {
30 typename T::ctype;
31 T::dim;
32 t.size();
34 { t.from_linear_index(size_t{}) } -> std::same_as<device::array<size_t, T::dim>>;
35 };
36
37 namespace internal
38 {
39 template <typename T, typename = void> struct coord_periodic : std::false_type {
40 };
41 template <typename T>
42 struct coord_periodic<T, std::void_t<decltype(T::periodic)>> : std::bool_constant<T::periodic> {
43 };
44 } // namespace internal
45
50 template <typename T> inline constexpr bool is_periodic_coordinate_v = internal::coord_periodic<T>::value;
51
52 namespace internal
53 {
54 template <typename C, size_t i, typename = void> struct axis_periodic : std::false_type {
55 };
56 template <typename C, size_t i>
57 struct axis_periodic<C, i, std::void_t<typename C::template coordinate_type<i>>>
58 : std::bool_constant<is_periodic_coordinate_v<typename C::template coordinate_type<i>>> {
59 };
60 } // namespace internal
61
66 template <typename C, size_t i> inline constexpr bool is_periodic_axis_v = internal::axis_periodic<C, i>::value;
67
68 namespace internal
69 {
71 template <typename NT> std::string round_trip(const NT value)
72 {
73 char buffer[40];
74 for (int precision = 6; precision < std::numeric_limits<NT>::max_digits10; ++precision) {
75 std::snprintf(buffer, sizeof(buffer), "%.*g", precision, double(value));
76 if (NT(std::strtod(buffer, nullptr)) == value) return std::string(buffer);
77 }
78 std::snprintf(buffer, sizeof(buffer), "%.*g", std::numeric_limits<NT>::max_digits10, double(value));
79 return std::string(buffer);
80 }
81 } // namespace internal
82
93 template <typename... Coordinates> class CoordinatePackND
94 {
95 // Assert that all coordinates have the same ctype
96 static_assert((std::is_same<typename Coordinates::ctype,
97 typename device::tuple_element<0, device::tuple<Coordinates...>>::type::ctype>::value &&
98 ...),
99 "CoordinatePackND: all coordinate systems must use the same ctype");
100 static_assert(sizeof...(Coordinates) > 0, "CoordinatePackND requires at least one coordinate system");
101 // Assert that all coordinates have the dim 1
102 static_assert(((Coordinates::dim == 1) && ...), "CoordinatePackND requires all coordinates to have dim 1");
103
104 public:
106 using ctype = typename device::tuple_element<0, device::tuple<Coordinates...>>::type::ctype;
108 static constexpr size_t dim = sizeof...(Coordinates);
109
112
116 template <typename... Coordinates2>
117 requires(sizeof...(Coordinates2) == sizeof...(Coordinates) &&
118 !std::is_same_v<CoordinatePackND<Coordinates2...>, CoordinatePackND> &&
119 (std::is_constructible_v<Coordinates, const Coordinates2 &> && ...))
121 : CoordinatePackND(other, std::index_sequence_for<Coordinates...>{})
122 {
123 }
124
126 template <typename... I>
127 requires(std::is_convertible_v<std::decay_t<I>, size_t> && ...)
128 KOKKOS_FORCEINLINE_FUNCTION device::array<ctype, dim> forward(I &&...i) const
129 {
130 static_assert(sizeof...(I) == sizeof...(Coordinates));
131 return forward_impl(device::make_integer_sequence<int, sizeof...(I)>(), device::forward<I>(i)...);
132 }
134 template <typename IT>
135 KOKKOS_FORCEINLINE_FUNCTION device::array<ctype, dim> forward(const device::array<IT, dim> &coords) const
136 {
137 return device::apply([&](const auto &...iargs) { return forward(iargs...); }, coords);
138 }
139
140 template <typename... I, int... Is>
141 device::array<ctype, dim> KOKKOS_FORCEINLINE_FUNCTION forward_impl(device::integer_sequence<int, Is...>,
142 I &&...i) const
143 {
144 return {{device::get<Is>(coordinates).forward(device::get<Is>(device::tie(i...)))...}};
145 }
146
148 template <typename... I> KOKKOS_FORCEINLINE_FUNCTION device::array<ctype, sizeof...(I)> backward(I &&...i) const
149 {
150 static_assert(sizeof...(I) == sizeof...(Coordinates));
151 return backward_impl(device::make_integer_sequence<int, sizeof...(I)>(), device::forward<I>(i)...);
152 }
153
154 template <typename... I, int... Is>
155 device::array<ctype, sizeof...(I)> KOKKOS_FORCEINLINE_FUNCTION backward_impl(device::integer_sequence<int, Is...>,
156 I &&...i) const
157 {
158 return {{device::get<Is>(coordinates).backward(device::get<Is>(device::tie(i...)))...}};
159 }
160
162 template <size_t i> const auto &get_coordinates() const { return device::get<i>(coordinates); }
163
167 template <size_t i>
168 using coordinate_type = typename device::tuple_element<i, device::tuple<Coordinates...>>::type;
169
171 size_t KOKKOS_FORCEINLINE_FUNCTION size() const
172 {
173 size_t size = 1;
174 constexpr_for<0, sizeof...(Coordinates), 1>([&](auto i) { size *= device::get<i>(coordinates).size(); });
175 return size;
176 }
177
179 device::array<size_t, sizeof...(Coordinates)> KOKKOS_FORCEINLINE_FUNCTION sizes() const
180 {
181 device::array<size_t, sizeof...(Coordinates)> sizes;
182 constexpr_for<0, sizeof...(Coordinates), 1>([&](auto i) { sizes[i] = device::get<i>(coordinates).size(); });
183 return sizes;
184 }
185
187 device::array<size_t, sizeof...(Coordinates)> KOKKOS_INLINE_FUNCTION from_linear_index(size_t s) const
188 {
189 device::array<size_t, sizeof...(Coordinates)> idx;
190 // calculate the index for each coordinate system
191 constexpr_for<0, sizeof...(Coordinates), 1>([&](auto i) {
192 idx[sizeof...(Coordinates) - 1 - i] = s % device::get<sizeof...(Coordinates) - 1 - i>(coordinates).size();
193 s = s / device::get<sizeof...(Coordinates) - 1 - i>(coordinates).size();
194 });
195
196 return idx;
197 }
198
200 template <typename... Coordinates2>
202 {
203 if constexpr (!std::is_same_v<device::tuple<Coordinates...>, device::tuple<Coordinates2...>>)
204 return false; // different axes
205 else {
206 // Check if all coordinates are equal
207 bool equal = true;
208 constexpr_for<0, sizeof...(Coordinates), 1>(
209 [&](auto i) { equal &= (device::get<i>(r.coordinates) == device::get<i>(l.coordinates)); });
210 return equal;
211 }
212 }
213
215 std::string to_string() const
216 {
217 std::string ret = "CoordinatePackND(";
218 constexpr_for<0, dim, 1>([&](auto i) {
219 ret += device::get<i>(coordinates).to_string();
220 if (i + 1 < dim) ret += ", ";
221 });
222 ret += ")";
223 return ret;
224 }
225
226 protected:
227 const device::tuple<Coordinates...> coordinates;
228
229 private:
230 template <typename Other, size_t... Is>
231 CoordinatePackND(const Other &other, std::index_sequence<Is...>)
232 : coordinates(Coordinates(other.template get_coordinates<Is>())...)
233 {
234 }
235 };
236
243 template <typename Base> class SubCoordinates : public Base
244 {
245 public:
246 using ctype = typename Base::ctype;
247 static constexpr size_t dim = Base::dim;
248
250 SubCoordinates(const Base &base, size_t offset, size_t size) : Base(base), m_offset(offset), m_size(size)
251 {
252 if (size == 0) throw std::runtime_error("SubCoordinates: size must be > 0");
253 if (offset + size > base.size()) throw std::runtime_error("SubCoordinates: offset + size must be <= base.size()");
254 }
255
257 device::array<size_t, dim> KOKKOS_FORCEINLINE_FUNCTION sizes() const
258 {
259 static_assert(dim == 1, "SubCoordinates is a linear index window, which is a per-axis box only for dim == 1.");
260 return device::array<size_t, dim>{{m_size}};
261 }
262
264 size_t KOKKOS_FORCEINLINE_FUNCTION size() const { return m_size; }
265
267 device::array<size_t, dim> KOKKOS_INLINE_FUNCTION from_linear_index(size_t s) const
268 {
269 return Base::from_linear_index(m_offset + s);
270 }
271
273 template <typename... I>
274 requires(std::is_convertible_v<std::decay_t<I>, size_t> && ...)
275 KOKKOS_FORCEINLINE_FUNCTION device::array<ctype, dim> forward(I &&...i) const
276 {
277 static_assert(sizeof...(I) == dim);
278 return forward(device::array<size_t, dim>{{static_cast<size_t>(i)...}});
279 }
280
282 template <typename IT> KOKKOS_INLINE_FUNCTION device::array<ctype, dim> forward(device::array<IT, dim> i) const
283 {
284 return Base::forward(i);
285 }
286
287 // backward() is Base's.
288
290 std::string to_string() const
291 {
292 return "SubCoordinates(" + Base::to_string() + ", " + std::to_string(m_offset) + ", " + std::to_string(m_size) +
293 ")";
294 }
295
296 private:
297 size_t m_offset;
298 size_t m_size;
299 };
300
309 template <typename NT = double>
310 requires std::is_floating_point_v<NT>
312 {
313 public:
315 using ctype = NT;
317 static constexpr size_t dim = 1;
318
320 LinearCoordinates1D(size_t grid_extent, double start, double stop)
321 : start(start), stop(stop), grid_extent(grid_extent), parent_extent(grid_extent)
322 {
323 if (grid_extent < 2) throw std::runtime_error("LinearCoordinates1D: grid_extent must be > 1");
324 a = (stop - start) / (grid_extent - 1.);
325 }
326
328 template <typename NT2>
330 : LinearCoordinates1D(LinearCoordinates1D(other.parent_size(), other.start, other.stop), other.size())
331 {
332 }
333
344 {
345 if (n < 1 || n > grid_extent) throw std::runtime_error("LinearCoordinates1D::prefix: need 1 <= n <= size()");
346 return LinearCoordinates1D(*this, n);
347 }
348
350 size_t KOKKOS_FORCEINLINE_FUNCTION parent_size() const { return parent_extent; }
351
353 device::array<size_t, 1> KOKKOS_FORCEINLINE_FUNCTION from_linear_index(size_t i) const
354 {
355 return device::array<size_t, 1>{i};
356 }
357
359 template <typename IT> NT KOKKOS_FORCEINLINE_FUNCTION forward(const IT &x) const { return start + a * x; }
360
362 template <typename IT> device::array<NT, 1> KOKKOS_FORCEINLINE_FUNCTION forward(const device::array<IT, 1> &x) const
363 {
364 return {forward(x[0])};
365 }
366
368 NT KOKKOS_FORCEINLINE_FUNCTION backward(const NT &y) const { return (y - start) / a; }
369
371 size_t KOKKOS_FORCEINLINE_FUNCTION size() const { return grid_extent; }
372
374 device::array<size_t, 1> KOKKOS_FORCEINLINE_FUNCTION sizes() const { return {grid_extent}; }
375
377 const NT start, stop;
378
380 template <typename NT2>
382 {
383 if constexpr (!std::is_same_v<NT, NT2>) return false; // Different types, cannot be equal
384 return lhs.start == rhs.start && lhs.stop == rhs.stop && lhs.size() == rhs.size() &&
385 lhs.parent_size() == rhs.parent_size();
386 }
387
389 std::string to_string() const
390 {
391 return "LinearCoordinates1D(" + std::to_string(parent_extent) + ", " + internal::round_trip(start) + ", " +
392 internal::round_trip(stop) + ")" +
393 (grid_extent == parent_extent ? std::string() : ".prefix(" + std::to_string(grid_extent) + ")");
394 }
395
396 private:
397 // prefix(): the parent's parameters and spacing, fewer points
398 LinearCoordinates1D(const LinearCoordinates1D &parent, size_t n)
399 : start(parent.start), stop(parent.stop), grid_extent(n), parent_extent(parent.parent_extent), a(parent.a)
400 {
401 }
402
403 const size_t grid_extent;
404 size_t parent_extent;
405 NT a;
406 };
407
417 template <typename NT = double>
418 requires std::is_floating_point_v<NT>
420 {
421 public:
423 using ctype = NT;
425 static constexpr size_t dim = 1;
427 static constexpr bool periodic = true;
428
430 LinearPeriodicCoordinates1D(size_t grid_extent, double start, double stop)
431 : start(start), stop(stop), grid_extent(grid_extent), extent(static_cast<NT>(grid_extent))
432 {
433 if (grid_extent == 0) throw std::runtime_error("LinearPeriodicCoordinates1D: grid_extent must be > 0");
434 a = (stop - start) / NT(grid_extent);
435 }
436
438 template <typename NT2>
443
445 device::array<size_t, 1> KOKKOS_FORCEINLINE_FUNCTION from_linear_index(size_t i) const
446 {
447 return device::array<size_t, 1>{i};
448 }
449
451 template <typename IT> NT KOKKOS_FORCEINLINE_FUNCTION forward(const IT &x) const { return start + a * x; }
452
454 template <typename IT> device::array<NT, 1> KOKKOS_FORCEINLINE_FUNCTION forward(const device::array<IT, 1> &x) const
455 {
456 return {forward(x[0])};
457 }
458
462 NT KOKKOS_FORCEINLINE_FUNCTION backward(const NT &y) const
463 {
464 using Kokkos::floor;
465 // fmod would keep the sign of idx, so fold explicitly into [0, grid_extent)
466 NT idx = (y - start) / a;
467 idx -= floor(idx / extent) * extent;
468 // right at the seam the division can round such that the fold leaves idx just outside the interval
469 if (idx >= extent) idx -= extent;
470 if (idx < NT(0)) idx = NT(0);
471 return idx;
472 }
473
475 size_t KOKKOS_FORCEINLINE_FUNCTION size() const { return grid_extent; }
476
478 device::array<size_t, 1> KOKKOS_FORCEINLINE_FUNCTION sizes() const { return {grid_extent}; }
479
481 const NT start, stop;
482
484 template <typename NT2>
486 {
487 if constexpr (!std::is_same_v<NT, NT2>) return false; // Different types, cannot be equal
488 return lhs.start == rhs.start && lhs.stop == rhs.stop && lhs.grid_extent == rhs.grid_extent;
489 }
490
492 std::string to_string() const
493 {
494 return "LinearPeriodicCoordinates1D(" + std::to_string(grid_extent) + ", " + internal::round_trip(start) + ", " +
495 internal::round_trip(stop) + ")";
496 }
497
498 private:
499 const size_t grid_extent;
500 const NT extent;
501 NT a;
502 };
503
514 template <typename NT = double>
515 requires std::is_floating_point_v<NT>
517 {
518 public:
520 using ctype = NT;
522 static constexpr size_t dim = 1;
523
526 LogarithmicCoordinates1D(size_t grid_extent, double start, double stop, double bias)
527 : start(start), stop(stop), bias(bias), grid_extent(grid_extent), parent_extent(grid_extent),
528 gem1(grid_extent - 1.), gem1inv(1. / (grid_extent - 1.)), a(bias), b((stop - start) / std::expm1(bias)),
529 c(start)
530 {
531 if (grid_extent < 2) throw std::runtime_error("LogarithmicCoordinates1D: grid_extent must be > 1");
532 if (bias == 0.) throw std::runtime_error("LogarithmicCoordinates1D: bias must be != 0");
533 }
534
536 template <typename NT2>
542
553 {
554 if (n < 1 || n > grid_extent) throw std::runtime_error("LogarithmicCoordinates1D::prefix: need 1 <= n <= size()");
555 return LogarithmicCoordinates1D(*this, n);
556 }
557
559 size_t KOKKOS_FORCEINLINE_FUNCTION parent_size() const { return parent_extent; }
560
562 device::array<size_t, 1> KOKKOS_FORCEINLINE_FUNCTION from_linear_index(size_t i) const
563 {
564 return device::array<size_t, 1>{i};
565 }
566
568 template <typename IT> NT KOKKOS_FORCEINLINE_FUNCTION forward(const IT &x) const
569 {
570 using Kokkos::expm1;
571 return b * expm1(a * x * gem1inv) + c;
572 }
573
575 template <typename IT> device::array<NT, 1> KOKKOS_FORCEINLINE_FUNCTION forward(const device::array<IT, 1> &x) const
576 {
577 return {forward(x[0])};
578 }
579
581 NT KOKKOS_FORCEINLINE_FUNCTION backward(const NT &y) const
582 {
583 using Kokkos::log1p;
584 return log1p((y - c) / b) * gem1 / a;
585 }
586
588 NT KOKKOS_FORCEINLINE_FUNCTION backward_derivative(const NT &y) const { return gem1 / (a * (b + y - c)); }
589
591 size_t KOKKOS_FORCEINLINE_FUNCTION size() const { return grid_extent; }
592
594 device::array<size_t, 1> KOKKOS_FORCEINLINE_FUNCTION sizes() const { return {grid_extent}; }
595
597 const NT start, stop, bias;
598
600 template <typename NT2>
602 {
603 if constexpr (!std::is_same_v<NT, NT2>) return false; // Different types, cannot be equal
604 return lhs.start == rhs.start && lhs.stop == rhs.stop && lhs.bias == rhs.bias && lhs.size() == rhs.size() &&
605 lhs.parent_size() == rhs.parent_size();
606 }
607
609 std::string to_string() const
610 {
611 return "LogarithmicCoordinates1D(" + internal::round_trip(start) + ", " + internal::round_trip(stop) + ", " +
612 internal::round_trip(bias) + ", " + std::to_string(parent_extent) + ")" +
613 (grid_extent == parent_extent ? std::string() : ".prefix(" + std::to_string(grid_extent) + ")");
614 }
615
616 private:
617 // prefix(): the parent's parameters and spacing (gem1 is the parent's N - 1), fewer points
619 : start(parent.start), stop(parent.stop), bias(parent.bias), grid_extent(n),
620 parent_extent(parent.parent_extent), gem1(parent.gem1), gem1inv(parent.gem1inv), a(parent.a), b(parent.b),
621 c(parent.c)
622 {
623 }
624
625 const size_t grid_extent;
626 size_t parent_extent;
627 const NT gem1, gem1inv;
628 NT a, b, c;
629 };
630
648 template <typename NT = double>
649 requires std::is_floating_point_v<NT>
651 {
652 public:
654 using ctype = NT;
656 static constexpr size_t dim = 1;
657
669 FocusedLogCoordinates1D(size_t grid_extent, double start, double stop, double center, double focus)
670 : start(start), stop(stop), center(center), focus(focus), grid_extent(grid_extent), parent_extent(grid_extent)
671 {
672 if (grid_extent < 2) throw std::runtime_error("FocusedLogCoordinates1D: grid_extent must be > 1");
673 if (!(start > 0.)) throw std::runtime_error("FocusedLogCoordinates1D: start must be > 0");
674 if (!(stop > start)) throw std::runtime_error("FocusedLogCoordinates1D: stop must be > start");
675 if (!(center > 0.)) throw std::runtime_error("FocusedLogCoordinates1D: center must be > 0");
676 if (!(focus >= 0.)) throw std::runtime_error("FocusedLogCoordinates1D: focus must be >= 0");
677
678 const double u_start = std::log(start);
679 const double u_stop = std::log(stop);
680 const double u0_d = std::log(center);
681 // sinh(s)/c is 0/0 at c == 0; below this threshold the map is a pure logarithmic grid to
682 // within round-off anyway, so switch to it explicitly.
683 pure_log = !(focus > 1e-8);
684
685 double s_min_d, a_d;
686 if (pure_log) {
687 // in this branch s *is* u, so forward() degenerates to start * exp(u - log(start))
688 s_min_d = u_start;
689 a_d = (u_stop - u_start) / double(grid_extent - 1);
690 } else {
691 s_min_d = s_of_u(u_start, focus, u0_d);
692 a_d = (s_of_u(u_stop, focus, u0_d) - s_min_d) / double(grid_extent - 1);
693 }
694 u0 = u0_d;
695 c = focus;
696 c_inv = pure_log ? NT(1) : NT(1. / focus);
697 s_min = s_min_d;
698 a = a_d;
699 a_inv = NT(1. / a_d);
700 // Store sinh(s_min), NOT sinh(s_min) * c_inv: forward() subtracts this BEFORE scaling by
701 // c_inv, which is what makes x == 0 cancel exactly. See the note in forward(). For the same
702 // reason it is evaluated in NT on the ROUNDED s_min, i.e. on exactly what forward() sees.
703 using Kokkos::sinh;
704 g_min = pure_log ? s_min : sinh(s_min);
705 }
706
708 template <typename NT2>
711 FocusedLogCoordinates1D(other.parent_size(), other.start, other.stop, other.center, other.focus),
712 other.size())
713 {
714 }
715
726 {
727 if (n < 1 || n > grid_extent) throw std::runtime_error("FocusedLogCoordinates1D::prefix: need 1 <= n <= size()");
728 return FocusedLogCoordinates1D(*this, n);
729 }
730
732 size_t KOKKOS_FORCEINLINE_FUNCTION parent_size() const { return parent_extent; }
733
735 device::array<size_t, 1> KOKKOS_FORCEINLINE_FUNCTION from_linear_index(size_t i) const
736 {
737 return device::array<size_t, 1>{i};
738 }
739
741 template <typename IT> NT KOKKOS_FORCEINLINE_FUNCTION forward(const IT &x) const
742 {
743 using Kokkos::exp, Kokkos::sinh;
744 const NT s = s_min + a * x;
745 // start * exp(...) and subtracting g_min before scaling by c_inv (no FMA contraction) make x == 0 give start
746 // exactly.
747 const NT d = pure_log ? (s - g_min) : (sinh(s) - g_min) * c_inv;
748 return start * exp(d);
749 }
750
752 template <typename IT> device::array<NT, 1> KOKKOS_FORCEINLINE_FUNCTION forward(const device::array<IT, 1> &x) const
753 {
754 return {forward(x[0])};
755 }
756
758 NT KOKKOS_FORCEINLINE_FUNCTION backward(const NT &y) const
759 {
760 using Kokkos::log;
761 const NT u = log(y);
762 return ((pure_log ? u : s_of_u(u, c, u0)) - s_min) * a_inv;
763 }
764
766 NT KOKKOS_FORCEINLINE_FUNCTION backward_derivative(const NT &y) const
767 {
768 using Kokkos::log, Kokkos::sqrt;
769 if (pure_log) return a_inv / y;
770 const NT v = c * (log(y) - u0);
771 return a_inv * c / (sqrt(v * v + NT(1)) * y);
772 }
773
775 size_t KOKKOS_FORCEINLINE_FUNCTION size() const { return grid_extent; }
776
778 device::array<size_t, 1> KOKKOS_FORCEINLINE_FUNCTION sizes() const { return {grid_extent}; }
779
781 const NT start, stop, center, focus;
782
784 template <typename NT2>
786 {
787 if constexpr (!std::is_same_v<NT, NT2>) return false; // Different types, cannot be equal
788 return lhs.start == rhs.start && lhs.stop == rhs.stop && lhs.center == rhs.center && lhs.focus == rhs.focus &&
789 lhs.size() == rhs.size() && lhs.parent_size() == rhs.parent_size();
790 }
791
793 std::string to_string() const
794 {
795 return "FocusedLogCoordinates1D(" + std::to_string(parent_extent) + ", " + internal::round_trip(start) + ", " +
796 internal::round_trip(stop) + ", " + internal::round_trip(center) + ", " + internal::round_trip(focus) +
797 ")" + (grid_extent == parent_extent ? std::string() : ".prefix(" + std::to_string(grid_extent) + ")");
798 }
799
800 private:
802 template <typename T> static KOKKOS_FORCEINLINE_FUNCTION T s_of_u(const T u, const T c, const T u0)
803 {
804 using Kokkos::log, Kokkos::sqrt;
805 const T v = c * (u - u0);
806 const T D = sqrt(v * v + T(1));
807 return v >= T(0) ? log(v + D) : -log(D - v);
808 }
809
810 // prefix(): the parent's parameters and spacing, fewer points
811 FocusedLogCoordinates1D(const FocusedLogCoordinates1D &parent, size_t n)
812 : start(parent.start), stop(parent.stop), center(parent.center), focus(parent.focus), grid_extent(n),
813 parent_extent(parent.parent_extent), u0(parent.u0), s_min(parent.s_min), a(parent.a), a_inv(parent.a_inv),
814 c(parent.c), c_inv(parent.c_inv), g_min(parent.g_min), pure_log(parent.pure_log)
815 {
816 }
817
818 const size_t grid_extent;
819 size_t parent_extent;
820 NT u0, s_min, a, a_inv, c, c_inv, g_min;
821 bool pure_log;
822 };
823
825 template <typename Coordinates> auto make_grid(const Coordinates &coordinates)
826 {
827 using ctype = typename Coordinates::ctype;
829 std::vector<cortype> grid(coordinates.size());
830 for (size_t i = 0; i < coordinates.size(); ++i) {
831 const auto forwarded = coordinates.forward(coordinates.from_linear_index(i));
832 for (size_t j = 0; j < Coordinates::dim; ++j) {
833 grid[i][j] = forwarded[j];
834 }
835 }
836 return grid;
837 }
838
840 template <typename Coordinates> std::vector<typename Coordinates::ctype> dump_grid(const Coordinates &coordinates)
841 {
842 using ctype = typename Coordinates::ctype;
843 std::vector<typename Coordinates::ctype> grid(coordinates.size() * Coordinates::dim);
844 for (size_t i = 0; i < coordinates.size(); ++i) {
845 for (size_t j = 0; j < Coordinates::dim; ++j) {
846 const auto forwarded = coordinates.forward(coordinates.from_linear_index(i));
847 grid[i * coordinates.dim + j] = forwarded[j];
848 }
849 }
850 return grid;
851 }
852
857 template <typename Coordinates, typename NT> struct rebind_ctype;
858 template <typename NT0, typename NT> struct rebind_ctype<LinearCoordinates1D<NT0>, NT> {
860 };
861 template <typename NT0, typename NT> struct rebind_ctype<LinearPeriodicCoordinates1D<NT0>, NT> {
863 };
864 template <typename NT0, typename NT> struct rebind_ctype<LogarithmicCoordinates1D<NT0>, NT> {
866 };
867 template <typename NT0, typename NT> struct rebind_ctype<FocusedLogCoordinates1D<NT0>, NT> {
869 };
870 template <typename... Cs, typename NT>
871 requires(requires { typename rebind_ctype<Cs, NT>::type; } && ...)
875 template <typename Coordinates, typename NT> using rebind_ctype_t = typename rebind_ctype<Coordinates, NT>::type;
876
877 // Common coordinate systems (double precision)
890
891 // Logarithmic coordinates focused on an interior scale, see FocusedLogCoordinates1D
896
897 // Periodic (angular) coordinates
908} // namespace DiFfRG
Product grid of one-dimensional coordinate systems.
Definition coordinates.hh:94
KOKKOS_FORCEINLINE_FUNCTION device::array< ctype, dim > forward(I &&...i) const
The coordinates of the point with indices i (one per axis; may be fractional).
Definition coordinates.hh:128
device::array< size_t, sizeof...(Coordinates)> KOKKOS_INLINE_FUNCTION from_linear_index(size_t s) const
The multi-index of the point with linear index s (row-major, last axis fastest).
Definition coordinates.hh:187
device::array< ctype, sizeof...(I)> KOKKOS_FORCEINLINE_FUNCTION backward_impl(device::integer_sequence< int, Is... >, I &&...i) const
Definition coordinates.hh:155
size_t KOKKOS_FORCEINLINE_FUNCTION size() const
Total number of points, the product of the axis sizes.
Definition coordinates.hh:171
KOKKOS_FORCEINLINE_FUNCTION device::array< ctype, dim > forward(const device::array< IT, dim > &coords) const
The coordinates of the point with multi-index coords.
Definition coordinates.hh:135
static constexpr size_t dim
Number of axes.
Definition coordinates.hh:108
typename device::tuple_element< i, device::tuple< Coordinates... > >::type coordinate_type
The type of the i-th axis. Used e.g. to query per-axis periodicity, see is_periodic_axis_v.
Definition coordinates.hh:168
std::string to_string() const
"CoordinatePackND(<axis 0>, <axis 1>, ...)"; identifies the grid, e.g. in HDF5 output.
Definition coordinates.hh:215
friend bool operator==(const CoordinatePackND< Coordinates... > &r, const CoordinatePackND< Coordinates2... > &l)
Equal if the axes have the same types and are pairwise equal; false for different axis types.
Definition coordinates.hh:201
const auto & get_coordinates() const
Axis i.
Definition coordinates.hh:162
CoordinatePackND(Coordinates... coordinates)
From the axes.
Definition coordinates.hh:111
CoordinatePackND(const CoordinatePackND< Coordinates2... > &other)
Convert from the same axes in another precision, e.g. float from double.
Definition coordinates.hh:120
device::array< size_t, sizeof...(Coordinates)> KOKKOS_FORCEINLINE_FUNCTION sizes() const
The size of each axis.
Definition coordinates.hh:179
device::array< ctype, dim > KOKKOS_FORCEINLINE_FUNCTION forward_impl(device::integer_sequence< int, Is... >, I &&...i) const
Definition coordinates.hh:141
typename device::tuple_element< 0, device::tuple< Coordinates... > >::type::ctype ctype
Scalar type.
Definition coordinates.hh:106
const device::tuple< Coordinates... > coordinates
Definition coordinates.hh:227
KOKKOS_FORCEINLINE_FUNCTION device::array< ctype, sizeof...(I)> backward(I &&...i) const
The (fractional) grid indices of the coordinates i, axis by axis.
Definition coordinates.hh:148
Points on [start, stop] (start > 0), logarithmically spaced and clustered around an interior scale ce...
Definition coordinates.hh:651
device::array< size_t, 1 > KOKKOS_FORCEINLINE_FUNCTION from_linear_index(size_t i) const
The multi-index {i} of point i.
Definition coordinates.hh:735
NT ctype
Scalar type.
Definition coordinates.hh:654
FocusedLogCoordinates1D(const FocusedLogCoordinates1D< NT2 > &other)
Convert from another precision.
Definition coordinates.hh:709
NT KOKKOS_FORCEINLINE_FUNCTION backward_derivative(const NT &y) const
at the coordinate y.
Definition coordinates.hh:766
NT KOKKOS_FORCEINLINE_FUNCTION backward(const NT &y) const
The inverse map: the (fractional) grid index of the coordinate y.
Definition coordinates.hh:758
size_t KOKKOS_FORCEINLINE_FUNCTION size() const
Number of points N.
Definition coordinates.hh:775
const NT center
Definition coordinates.hh:781
FocusedLogCoordinates1D prefix(size_t n) const
The first n points of this grid, as a grid of the same type.
Definition coordinates.hh:725
static constexpr size_t dim
One axis.
Definition coordinates.hh:656
friend bool operator==(const FocusedLogCoordinates1D< NT > &lhs, const FocusedLogCoordinates1D< NT2 > &rhs)
Same precision, parameters and number of points (and the same parent, for a prefix).
Definition coordinates.hh:785
std::string to_string() const
"FocusedLogCoordinates1D(N, start, stop, center, focus)"; identifies the grid.
Definition coordinates.hh:793
const NT stop
Definition coordinates.hh:781
size_t KOKKOS_FORCEINLINE_FUNCTION parent_size() const
Number of points of the grid this one is a prefix() of; size() unless it is a prefix.
Definition coordinates.hh:732
NT KOKKOS_FORCEINLINE_FUNCTION forward(const IT &x) const
The coordinate at grid index x (real values allowed).
Definition coordinates.hh:741
const NT focus
Definition coordinates.hh:781
device::array< NT, 1 > KOKKOS_FORCEINLINE_FUNCTION forward(const device::array< IT, 1 > &x) const
As forward(x[0]).
Definition coordinates.hh:752
FocusedLogCoordinates1D(size_t grid_extent, double start, double stop, double center, double focus)
The grid; throws if a parameter is out of range.
Definition coordinates.hh:669
const NT start
The parameters.
Definition coordinates.hh:781
device::array< size_t, 1 > KOKKOS_FORCEINLINE_FUNCTION sizes() const
{N}.
Definition coordinates.hh:778
Equally spaced points on [start, stop], including both ends.
Definition coordinates.hh:312
device::array< size_t, 1 > KOKKOS_FORCEINLINE_FUNCTION from_linear_index(size_t i) const
The multi-index {i} of point i.
Definition coordinates.hh:353
NT ctype
Scalar type.
Definition coordinates.hh:315
friend bool operator==(const LinearCoordinates1D< NT > &lhs, const LinearCoordinates1D< NT2 > &rhs)
Same precision, parameters and number of points (and the same parent, for a prefix).
Definition coordinates.hh:381
LinearCoordinates1D(const LinearCoordinates1D< NT2 > &other)
Convert from another precision.
Definition coordinates.hh:329
NT KOKKOS_FORCEINLINE_FUNCTION backward(const NT &y) const
The inverse map: the (fractional) grid index of the coordinate y.
Definition coordinates.hh:368
size_t KOKKOS_FORCEINLINE_FUNCTION size() const
Number of points N.
Definition coordinates.hh:371
LinearCoordinates1D prefix(size_t n) const
The first n points of this grid, as a grid of the same type.
Definition coordinates.hh:343
static constexpr size_t dim
One axis.
Definition coordinates.hh:317
std::string to_string() const
"LinearCoordinates1D(N, start, stop)"; identifies the grid, e.g. in HDF5 output.
Definition coordinates.hh:389
const NT stop
Definition coordinates.hh:377
LinearCoordinates1D(size_t grid_extent, double start, double stop)
grid_extent points (≥ 2, throws otherwise) from start to stop.
Definition coordinates.hh:320
size_t KOKKOS_FORCEINLINE_FUNCTION parent_size() const
Number of points of the grid this one is a prefix() of; size() unless it is a prefix.
Definition coordinates.hh:350
NT KOKKOS_FORCEINLINE_FUNCTION forward(const IT &x) const
The coordinate at grid index x (real values allowed).
Definition coordinates.hh:359
device::array< NT, 1 > KOKKOS_FORCEINLINE_FUNCTION forward(const device::array< IT, 1 > &x) const
As forward(x[0]).
Definition coordinates.hh:362
const NT start
First and last point.
Definition coordinates.hh:377
device::array< size_t, 1 > KOKKOS_FORCEINLINE_FUNCTION sizes() const
{N}.
Definition coordinates.hh:374
Equally spaced points on a periodic axis of period stop - start; stop itself is excluded.
Definition coordinates.hh:420
device::array< size_t, 1 > KOKKOS_FORCEINLINE_FUNCTION from_linear_index(size_t i) const
The multi-index {i} of point i.
Definition coordinates.hh:445
NT ctype
Scalar type.
Definition coordinates.hh:423
LinearPeriodicCoordinates1D(const LinearPeriodicCoordinates1D< NT2 > &other)
Convert from another precision.
Definition coordinates.hh:439
friend bool operator==(const LinearPeriodicCoordinates1D< NT > &lhs, const LinearPeriodicCoordinates1D< NT2 > &rhs)
Same precision, parameters and number of points.
Definition coordinates.hh:485
NT KOKKOS_FORCEINLINE_FUNCTION backward(const NT &y) const
The inverse map: the (fractional) grid index of the coordinate y, folded into [0, N).
Definition coordinates.hh:462
size_t KOKKOS_FORCEINLINE_FUNCTION size() const
Number of points N.
Definition coordinates.hh:475
static constexpr size_t dim
One axis.
Definition coordinates.hh:425
std::string to_string() const
"LinearPeriodicCoordinates1D(N, start, stop)"; identifies the grid.
Definition coordinates.hh:492
LinearPeriodicCoordinates1D(size_t grid_extent, double start, double stop)
grid_extent points (≥ 1, throws otherwise) on the period [start, stop).
Definition coordinates.hh:430
const NT stop
Definition coordinates.hh:481
NT KOKKOS_FORCEINLINE_FUNCTION forward(const IT &x) const
The coordinate at grid index x (real values allowed).
Definition coordinates.hh:451
device::array< NT, 1 > KOKKOS_FORCEINLINE_FUNCTION forward(const device::array< IT, 1 > &x) const
As forward(x[0]).
Definition coordinates.hh:454
const NT start
Ends of the period.
Definition coordinates.hh:481
device::array< size_t, 1 > KOKKOS_FORCEINLINE_FUNCTION sizes() const
{N}.
Definition coordinates.hh:478
static constexpr bool periodic
Marks the axis as periodic.
Definition coordinates.hh:427
Points on [start, stop], including both ends, with spacing growing exponentially in the index.
Definition coordinates.hh:517
device::array< size_t, 1 > KOKKOS_FORCEINLINE_FUNCTION from_linear_index(size_t i) const
The multi-index {i} of point i.
Definition coordinates.hh:562
NT ctype
Scalar type.
Definition coordinates.hh:520
LogarithmicCoordinates1D(size_t grid_extent, double start, double stop, double bias)
Definition coordinates.hh:526
friend bool operator==(const LogarithmicCoordinates1D< NT > &lhs, const LogarithmicCoordinates1D< NT2 > &rhs)
Same precision, parameters and number of points (and the same parent, for a prefix).
Definition coordinates.hh:601
LogarithmicCoordinates1D prefix(size_t n) const
The first n points of this grid, as a grid of the same type.
Definition coordinates.hh:552
NT KOKKOS_FORCEINLINE_FUNCTION backward_derivative(const NT &y) const
at the coordinate y.
Definition coordinates.hh:588
NT KOKKOS_FORCEINLINE_FUNCTION backward(const NT &y) const
The inverse map: the (fractional) grid index of the coordinate y.
Definition coordinates.hh:581
size_t KOKKOS_FORCEINLINE_FUNCTION size() const
Number of points N.
Definition coordinates.hh:591
static constexpr size_t dim
One axis.
Definition coordinates.hh:522
std::string to_string() const
"LogarithmicCoordinates1D(start, stop, bias, N)"; identifies the grid.
Definition coordinates.hh:609
const NT stop
Definition coordinates.hh:597
LogarithmicCoordinates1D(const LogarithmicCoordinates1D< NT2 > &other)
Convert from another precision.
Definition coordinates.hh:537
size_t KOKKOS_FORCEINLINE_FUNCTION parent_size() const
Number of points of the grid this one is a prefix() of; size() unless it is a prefix.
Definition coordinates.hh:559
NT KOKKOS_FORCEINLINE_FUNCTION forward(const IT &x) const
The coordinate at grid index x (real values allowed).
Definition coordinates.hh:568
const NT bias
Definition coordinates.hh:597
device::array< NT, 1 > KOKKOS_FORCEINLINE_FUNCTION forward(const device::array< IT, 1 > &x) const
As forward(x[0]).
Definition coordinates.hh:575
const NT start
The parameters.
Definition coordinates.hh:597
device::array< size_t, 1 > KOKKOS_FORCEINLINE_FUNCTION sizes() const
{N}.
Definition coordinates.hh:594
The points with linear indices [offset, offset + size) of another coordinate system Base.
Definition coordinates.hh:244
KOKKOS_FORCEINLINE_FUNCTION device::array< ctype, dim > forward(I &&...i) const
Base::forward of the Base indices i.
Definition coordinates.hh:275
SubCoordinates(const Base &base, size_t offset, size_t size)
The window [offset, offset + size) of base; throws if empty or out of range.
Definition coordinates.hh:250
device::array< size_t, dim > KOKKOS_INLINE_FUNCTION from_linear_index(size_t s) const
Base's multi-index of the window's s-th point.
Definition coordinates.hh:267
device::array< size_t, dim > KOKKOS_FORCEINLINE_FUNCTION sizes() const
Per-axis extents; only defined for dim == 1 (a linear window is not a box otherwise).
Definition coordinates.hh:257
size_t KOKKOS_FORCEINLINE_FUNCTION size() const
Number of points in the window.
Definition coordinates.hh:264
KOKKOS_INLINE_FUNCTION device::array< ctype, dim > forward(device::array< IT, dim > i) const
Base::forward of a Base multi-index (as returned by from_linear_index()).
Definition coordinates.hh:282
typename Base::ctype ctype
Definition coordinates.hh:246
static constexpr size_t dim
Definition coordinates.hh:247
std::string to_string() const
"SubCoordinates(<base>, offset, size)"; identifies the window.
Definition coordinates.hh:290
A coordinate system: a map from grid indices to physical coordinates.
Definition coordinates.hh:29
Execution and memory spaces, and Kokkos helpers.
std::tuple< T... > tuple
Definition kokkos.hh:122
std::array< T, N > array
Definition kokkos.hh:123
Definition complex_math.hh:20
constexpr bool is_periodic_axis_v
Whether axis i of a (possibly multi-dimensional) coordinate system is periodic. Falls back to false f...
Definition coordinates.hh:66
auto make_grid(const Coordinates &coordinates)
All grid points, in linear index order, as arrays of dim coordinates.
Definition coordinates.hh:825
std::vector< typename Coordinates::ctype > dump_grid(const Coordinates &coordinates)
All grid points, in linear index order, flattened: point i occupies entries [i dim,...
Definition coordinates.hh:840
constexpr bool is_periodic_coordinate_v
Whether a 1D coordinate class describes a periodic axis, i.e. one where the last grid point is follow...
Definition coordinates.hh:50
typename rebind_ctype< Coordinates, NT >::type rebind_ctype_t
Definition coordinates.hh:875
constexpr void constexpr_for(F &&f)
Compile-time loop: calls f(i) for i = Start, Start + Inc, ... while i < End.
Definition utils.hh:37
The same coordinate system with ctype NT, e.g. the float twin of a double grid: rebind_ctype_t<Coordi...
Definition coordinates.hh:857