Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
TransformGhostLayer.cpp
Go to the documentation of this file.
1// -------------------------------------------------------//
2//
3// SHAMROCK code for hydrodynamics
4// Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me>
5// SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1
6// Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information
7//
8// -------------------------------------------------------//
9
16#include "shambase/assert.hpp"
21#include "shammath/AABB.hpp"
29#include <stdexcept>
30#include <vector>
31
32template<class Tvec, class TgridVec>
35 auto edges = get_edges();
36
37 // inputs
38 auto &sim_box = edges.sim_box.value;
39 auto &ghost_layers_candidates = edges.ghost_layers_candidates;
40
41 // outputs
42 auto &ghost_layer = edges.ghost_layer;
43
44 auto dev_sched = shamsys::instance::get_compute_scheduler_ptr();
45 sham::DeviceQueue &q = shambase::get_check_ref(dev_sched).get_queue();
46
47 auto paving_function = get_paving(mode, sim_box);
48
49 // get the block min and max field
50 u32 iblock_min = ghost_layer_layout->get_field_idx<TgridVec>("cell_min");
51 u32 iblock_max = ghost_layer_layout->get_field_idx<TgridVec>("cell_max");
52
53 // extract the ghost layers
54 auto ghost_layer_it = ghost_layer.patchdatas.begin();
55 auto ghost_layer_info_it = ghost_layers_candidates.values.begin();
56
57 if (ghost_layer.patchdatas.get_element_count()
58 != ghost_layers_candidates.values.get_element_count()) {
60 "ghost_layer.patchdatas.get_element_count() != "
61 "ghost_layers_candidates.values.get_element_count()\n "
62 "ghost_layer.patchdatas.get_element_count(): {}\n"
63 "ghost_layers_candidates.values.get_element_count(): {}",
64 ghost_layer.patchdatas.get_element_count(),
65 ghost_layers_candidates.values.get_element_count()));
66 }
67
68 // iterate on both DDShared containers
69 for (; ghost_layer_it != ghost_layer.patchdatas.end();
70 ++ghost_layer_it, ++ghost_layer_info_it) {
71
72 auto [sender, receiver] = ghost_layer_it->first;
73
74 shamrock::patch::PatchDataLayer &ghost_layer_element = ghost_layer_it->second;
75 auto &sender_ghost_layer_info = ghost_layer_info_it->second;
76
77 auto &block_min_buf = ghost_layer_element.get_field<TgridVec>(iblock_min).get_buf();
78 auto &block_max_buf = ghost_layer_element.get_field<TgridVec>(iblock_max).get_buf();
79 auto xoff = sender_ghost_layer_info.xoff;
80 auto yoff = sender_ghost_layer_info.yoff;
81 auto zoff = sender_ghost_layer_info.zoff;
82 // transform the block min and max
84 q,
86 sham::MultiRef{block_min_buf, block_max_buf},
87 ghost_layer_element.get_obj_cnt(),
88 [paving_function, xoff, yoff, zoff](
89 u32 i, TgridVec *__restrict block_min, TgridVec *__restrict block_max) {
90 shammath::AABB<TgridVec> block_box = {block_min[i], block_max[i]};
91
92 block_box = paving_function.f_aabb(block_box, xoff, yoff, zoff);
93
94 block_min[i] = block_box.lower;
95 block_max[i] = block_box.upper;
96 });
97
98 // do not forget that while we have transformed the ghost layer block bound we did not
99 // transform the ghost layer data Especially if the paving is reflexive a permutation needs
100 // to be applied to the ghost layer data
101
103 static constexpr u32 block_size = AMRBlock::block_size;
104 static constexpr u32 expected_nvar = AMRBlock::block_size;
106
107 auto compute_field_var_permut = [&paving_function, xoff, yoff, zoff]() -> std::vector<u32> {
108 // get coord list per cell in the block
109 std::array<std::array<u32, dim>, block_size> coord_list = {};
110 for (u32 i = 0; i < block_size; i++) {
111 coord_list[i] = AMRBlock::get_coord(i);
112 }
113
114 // apply the paving function to the coord list
115 std::array<TgridVec, block_size> coord_list_transformed = {};
116 for (u32 i = 0; i < block_size; i++) {
117 TgridVec coord = {coord_list[i][0], coord_list[i][1], coord_list[i][2]};
118 coord_list_transformed[i] = paving_function.f(coord, xoff, yoff, zoff);
119 }
120
121 // get the min and max coord in the block
122 TgridVec min_coord = coord_list_transformed[0];
123 TgridVec max_coord = coord_list_transformed[0];
124 for (u32 i = 1; i < block_size; i++) {
125 min_coord = sham::min(min_coord, coord_list_transformed[i]);
126 max_coord = sham::max(max_coord, coord_list_transformed[i]);
127 }
128
129 // compute the permut
130 std::vector<u32> permut(block_size);
131 for (u32 i = 0; i < block_size; i++) {
132 TgridVec new_coord = coord_list_transformed[i] - min_coord;
133 std::array<u32, dim> new_coord_arr
134 = {static_cast<u32>(new_coord[0]),
135 static_cast<u32>(new_coord[1]),
136 static_cast<u32>(new_coord[2])};
137 permut[i] = AMRBlock::get_index(new_coord_arr);
138 }
139
140 return permut;
141 };
142
143 std::vector<u32> permut = compute_field_var_permut();
144
145 // apply the permut to the field
146 auto apply_permut = [&](auto &field) {
147 u32 nvar = field.get_nvar();
148
149 if (nvar == expected_nvar) {
150 field.permut_vars(permut);
151 } else if (nvar % expected_nvar == 0) {
152
153 u32 fact_expand = nvar / expected_nvar;
154
155 std::vector<u32> new_permut(nvar);
156 for (u32 i = 0; i < expected_nvar; i++) {
157 for (u32 j = 0; j < fact_expand; j++) {
158 new_permut[i * fact_expand + j] = permut[i] * fact_expand + j;
159 }
160 }
161 field.permut_vars(new_permut);
162 } else if (nvar == 1) {
163 // do nothing
164 } else {
166 "the number of variables is not equal to the expected number of variables: {} "
167 "!= {}, field name: {}, layout: {}",
168 nvar,
169 expected_nvar,
170 field.get_name(),
171 ghost_layer_element.get_layout_ptr()->get_description_str()));
172 }
173 };
174
175 ghost_layer_element.for_each_field_any(apply_permut);
176
177 // Ok this is wierd but it works
178 // The idea is that the paving does not deform, it only translates and invert. As such
179 // if we supply two points whose difference is 1 in every compoenent, the diff after paving
180 // is the termwise multiplication to be applied to vector quantities.
181 // Periodic x:
182 // (0,0,0) -> (1,1,1) becomes (1,1,1) -> (2,2,2), delta = (1,1,1)
183 // Reflective x:
184 // (0,0,0) -> (1,1,1) becomes (1,1,1) -> (0,2,2), delta = (-1,1,1)
185 // so a vector get its x component inverted
186 // TODO: add that to the doc on paving functions
187 auto get_termwise_mul_vec = [&]() {
188 TgridVec p0 = {0, 0, 0};
189 TgridVec p1 = {1, 1, 1};
190
191 TgridVec p0_transformed = paving_function.f(p0, xoff, yoff, zoff);
192 TgridVec p1_transformed = paving_function.f(p1, xoff, yoff, zoff);
193
194 TgridVec mul_compo_vec = p1_transformed - p0_transformed;
195
196 return mul_compo_vec;
197 };
198
199 using Tscal = typename shambase::VectorProperties<Tvec>::component_type;
200
201 auto mul_compo_vec = get_termwise_mul_vec().template convert<Tscal>();
202
203 auto transform_vecs = [&](auto &field) {
204 using T = typename std::decay_t<decltype(field)>::Field_type;
205 if constexpr (std::is_same_v<T, Tvec>) {
206 auto &buf = field.get_buf();
208 q,
210 sham::MultiRef{buf},
211 field.get_obj_cnt() * field.get_nvar(),
212 [mul_compo_vec](u32 i, Tvec *__restrict vec) {
213 vec[i] = vec[i] * mul_compo_vec;
214 });
215 } else if constexpr (std::is_same_v<T, TgridVec>) {
216 } else if constexpr (std::is_same_v<T, Tscal>) {
217 } else {
219 }
220 };
221
222 if ((xoff != 0 && transform_vec_x) || (yoff != 0 && transform_vec_y)
223 || (zoff != 0 && transform_vec_z)) {
224 ghost_layer_element.for_each_field_any(transform_vecs);
225 }
226 }
227}
228
229template<class Tvec, class TgridVec>
234
utility to manipulate AMR blocks
Header file describing a Node Instance.
Field variant object to instanciate a variant on the patch types.
std::uint32_t u32
32 bit unsigned integer
Shamrock assertion utility.
A SYCL queue associated with a device and a context.
virtual std::string _impl_get_tex() const
get the tex of the node
PatchDataLayer container class, the layout is described in patchdata_layout.
This header file contains utility functions related to exception handling in the code.
void kernel_call(sham::DeviceQueue &q, RefIn in, RefOut in_out, u32 n, Functor &&func, SourceLocation &&callsite=SourceLocation{})
Submit a kernel to a SYCL queue.
void throw_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Throw an exception and append the source location to it.
T & get_check_ref(const std::unique_ptr< T > &ptr, SourceLocation loc=SourceLocation())
Takes a std::unique_ptr and returns a reference to the object it holds. It throws a std::runtime_erro...
Definition memory.hpp:110
void throw_unimplemented(SourceLocation loc=SourceLocation{})
Throw a std::runtime_error saying that the function is unimplemented.
A class that references multiple buffers or similar objects.
Axis-Aligned bounding box.
Definition AABB.hpp:99
T lower
Lower bound of the AABB.
Definition AABB.hpp:104
T upper
Upper bound of the AABB.
Definition AABB.hpp:105
utility class to handle AMR blocks
Definition AMRBlock.hpp:35