/home/runner/work/DiFfRG_current/DiFfRG_current/DiFfRG/include/DiFfRG/physics/interpolation/linear_interpolator_3d.hh Source File#

DiFfRG: /home/runner/work/DiFfRG_current/DiFfRG_current/DiFfRG/include/DiFfRG/physics/interpolation/linear_interpolator_3d.hh Source File
DiFfRG
linear_interpolator_3d.hh
Go to the documentation of this file.
1#pragma once
2
3// DiFfRG
7
8namespace DiFfRG
9{
16 template <typename NT, typename Coordinates, typename DefaultMemorySpace = CPU_memory> class LinearInterpolator3D
17 {
18 static_assert(Coordinates::dim == 3, "LinearInterpolator3D requires 3D coordinates");
19
20 public:
21 using memory_space = DefaultMemorySpace;
23 using ctype = typename Coordinates::ctype;
24 using value_type = NT;
25 static constexpr size_t dim = 3;
26
35 {
36 // Allocate Kokkos View
37 device_data = ViewType("LinearInterpolator3D_data", sizes[0], sizes[1], sizes[2]);
38 // Create host mirror
39 host_data = Kokkos::create_mirror_view(device_data);
40 }
41
42 KOKKOS_FUNCTION
45 {
46 // Use the same data
48 }
49
50 KOKKOS_FUNCTION ~LinearInterpolator3D()
51 {
52 KOKKOS_IF_ON_HOST((if (owns_other_instance) delete other_instance;))
53 }
54
55 template <typename NT2> void update(const NT2 *in_data)
56 {
57 // Check if the host data is already allocated
58 if (!host_data.is_allocated())
59 throw std::runtime_error(
60 "LinearInterpolator3D: You probably called update() on a copied instance. This is not allowed. "
61 "You need to call update() on the original instance.");
62 // Populate host mirror
63 Kokkos::View<const NT2 ***, Kokkos::LayoutRight, Kokkos::HostSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>
64 in_view(in_data, sizes[0], sizes[1], sizes[2]);
65 update(in_view);
66 }
67
68 template <typename View>
69 requires Kokkos::is_view<View>::value
70 void update(const View &view)
71 {
72 // Check if the host data is already allocated
73 if (!host_data.is_allocated())
74 throw std::runtime_error(
75 "LinearInterpolator2D: You probably called update() on a copied instance. This is not allowed. "
76 "You need to call update() on the original instance.");
77 // Populate host mirror
78 Kokkos::deep_copy(host_data, view);
79 // Copy data to device
80 Kokkos::deep_copy(device_data, host_data);
81 }
82
83 NT operator[](size_t i) const
84 {
85 // Check if the host data is already allocated
86 if (!host_data.is_allocated())
87 throw std::runtime_error(
88 "LinearInterpolator3D: You probably called operator[]() on a copied instance. This is not allowed. "
89 "You need to call operator[]() on the original instance.");
90 return host_data.data()[i]; // Access the host data directly
91 }
92
99 NT KOKKOS_FUNCTION operator()(const ctype &x, const ctype &y, const ctype &z) const
100 {
101 using Kokkos::min, Kokkos::max;
102 auto [idx_x, idx_y, idx_z] = coordinates.backward(x, y, z);
103 idx_x = max(static_cast<decltype(idx_x)>(0), min(idx_x, static_cast<decltype(idx_x)>(sizes[0] - 1)));
104 idx_y = max(static_cast<decltype(idx_y)>(0), min(idx_y, static_cast<decltype(idx_y)>(sizes[1] - 1)));
105 idx_z = max(static_cast<decltype(idx_z)>(0), min(idx_z, static_cast<decltype(idx_z)>(sizes[2] - 1)));
106
107 // Lower index clamped to [0, sizes-2], upper = lower+1
108 const size_t x0 = min(size_t(Kokkos::floor(idx_x)), sizes[0] - 2);
109 const size_t y0 = min(size_t(Kokkos::floor(idx_y)), sizes[1] - 2);
110 const size_t z0 = min(size_t(Kokkos::floor(idx_z)), sizes[2] - 2);
111 const size_t x1 = x0 + 1;
112 const size_t y1 = y0 + 1;
113 const size_t z1 = z0 + 1;
114
115 const auto corner000 = device_data(x0, y0, z0);
116 const auto corner010 = device_data(x0, y1, z0);
117 const auto corner100 = device_data(x1, y0, z0);
118 const auto corner110 = device_data(x1, y1, z0);
119 const auto corner001 = device_data(x0, y0, z1);
120 const auto corner011 = device_data(x0, y1, z1);
121 const auto corner101 = device_data(x1, y0, z1);
122 const auto corner111 = device_data(x1, y1, z1);
123
124 const auto tx = idx_x - x0;
125 const auto ty = idx_y - y0;
126 const auto tz = idx_z - z0;
127
128 if constexpr (std::is_arithmetic_v<NT>)
129 return Kokkos::fma(
130 tx,
131 Kokkos::fma(ty, Kokkos::fma(tz, corner111, Kokkos::fma(-tz, corner110, corner110)),
132 (1 - ty) * Kokkos::fma(tz, corner101, Kokkos::fma(-tz, corner100, corner100))),
133 (1 - tx) * Kokkos::fma(ty, Kokkos::fma(tz, corner011, Kokkos::fma(-tz, corner010, corner010)),
134 (1 - ty) * Kokkos::fma(tz, corner001, Kokkos::fma(-tz, corner000, corner000))));
135 else
136 return corner000 * (1 - tx) * (1 - ty) * (1 - tz) + corner001 * (1 - tx) * (1 - ty) * tz +
137 corner010 * (1 - tx) * ty * (1 - tz) + corner011 * (1 - tx) * ty * tz +
138 corner100 * tx * (1 - ty) * (1 - tz) + corner101 * tx * (1 - ty) * tz +
139 corner110 * tx * ty * (1 - tz) + corner111 * tx * ty * tz;
140 }
141
142 auto &CPU() const { return get_on<CPU_memory>(); }
143 auto &GPU() const { return get_on<GPU_memory>(); }
144
145 template <typename MemorySpace> auto &get_on() const
146 {
147 // Check if the host data is already allocated
148 if (!host_data.is_allocated())
149 throw std::runtime_error(
150 "LinearInterpolator3D: You probably called get_on[]() on a copied instance. This is not allowed. "
151 "You need to call get_on[]() on the original instance.");
152
153 if constexpr (std::is_same_v<MemorySpace, DefaultMemorySpace>) {
154 // remove constness
155 return const_cast<LinearInterpolator3D<NT, Coordinates, MemorySpace> &>(*this);
156 } else {
157 // Create a new instance with the same data but in the requested memory space
158 if (other_instance == nullptr) {
160 owns_other_instance = true;
161 other_instance->other_instance = const_cast<std::decay_t<decltype(*this)> *>(this);
162 }
163 // Copy the data from the current instance to the new one
164 other_instance->update(host_data);
165 // Return the new instance
166 return *other_instance;
167 }
168 }
169
175 const Coordinates &get_coordinates() const { return coordinates; }
176
177 NT *data()
178 {
179 if (!host_data.is_allocated())
180 throw std::runtime_error(
181 "LinearInterpolator1D: You probably called data() on a copied instance. This is not allowed. "
182 "You need to call data() on the original instance.");
183 return host_data.data();
184 }
185
186 friend class LinearInterpolator3D<NT, Coordinates, other_memory_space>;
187
188 private:
189 const Coordinates coordinates;
191 const size_t total_size;
192
193 using ViewType = Kokkos::View<NT ***, DefaultMemorySpace, Kokkos::MemoryTraits<Kokkos::RandomAccess>>;
194 using HostViewType = typename ViewType::host_mirror_type;
195
198
200 mutable bool owns_other_instance = false;
201 };
202} // namespace DiFfRG
A linear interpolator for 3D data, both on GPU and CPU.
Definition linear_interpolator_3d.hh:17
KOKKOS_FUNCTION LinearInterpolator3D(const LinearInterpolator3D &other)
Definition linear_interpolator_3d.hh:43
auto & GPU() const
Definition linear_interpolator_3d.hh:143
DefaultMemorySpace memory_space
Definition linear_interpolator_3d.hh:21
const size_t total_size
Definition linear_interpolator_3d.hh:191
NT value_type
Definition linear_interpolator_3d.hh:24
void update(const View &view)
Definition linear_interpolator_3d.hh:70
const Coordinates coordinates
Definition linear_interpolator_3d.hh:189
ViewType device_data
Definition linear_interpolator_3d.hh:196
Kokkos::View< NT ***, DefaultMemorySpace, Kokkos::MemoryTraits< Kokkos::RandomAccess > > ViewType
Definition linear_interpolator_3d.hh:193
typename ViewType::host_mirror_type HostViewType
Definition linear_interpolator_3d.hh:194
other_memory_space_t< DefaultMemorySpace > other_memory_space
Definition linear_interpolator_3d.hh:22
HostViewType host_data
Definition linear_interpolator_3d.hh:197
LinearInterpolator3D(const Coordinates &coordinates)
Construct a LinearInterpolator3D with internal, zeroed data and a coordinate system.
Definition linear_interpolator_3d.hh:33
static constexpr size_t dim
Definition linear_interpolator_3d.hh:25
NT * data()
Definition linear_interpolator_3d.hh:177
NT operator[](size_t i) const
Definition linear_interpolator_3d.hh:83
void update(const NT2 *in_data)
Definition linear_interpolator_3d.hh:55
auto & get_on() const
Definition linear_interpolator_3d.hh:145
typename Coordinates::ctype ctype
Definition linear_interpolator_3d.hh:23
KOKKOS_FUNCTION ~LinearInterpolator3D()
Definition linear_interpolator_3d.hh:50
auto & CPU() const
Definition linear_interpolator_3d.hh:142
NT KOKKOS_FUNCTION operator()(const ctype &x, const ctype &y, const ctype &z) const
Interpolate the data at a given point.
Definition linear_interpolator_3d.hh:99
LinearInterpolator3D< NT, Coordinates, other_memory_space > * other_instance
Definition linear_interpolator_3d.hh:199
const device::array< size_t, 3 > sizes
Definition linear_interpolator_3d.hh:190
bool owns_other_instance
Definition linear_interpolator_3d.hh:200
const Coordinates & get_coordinates() const
Get the coordinate system of the data.
Definition linear_interpolator_3d.hh:175
std::array< T, N > array
Definition kokkos.hh:133
Definition complex_math.hh:10
std::conditional_t< std::is_same_v< MemorySpace, GPU_memory >, CPU_memory, GPU_memory > other_memory_space_t
Definition kokkos.hh:58