Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
scheduler_patch_list.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
15
17#include "nlohmann/json_fwd.hpp"
22#include <random>
23#include <vector>
24
26 StackEntry stack_loc{};
27
28 using namespace shamrock::patch;
29
31 local, get_patch_mpi_type<3>(), global, get_patch_mpi_type<3>(), MPI_COMM_WORLD);
32}
33
34std::unordered_set<u64> SchedulerPatchList::build_local() {
35 StackEntry stack_loc{};
36
37 std::unordered_set<u64> out_ids;
38
39 local.clear();
40 for (const shamrock::patch::Patch &p : global) {
41 // TODO add check node_owner_id valid
42 if (i32(p.node_owner_id) == shamcomm::world_rank()) {
43 local.push_back(p);
44 out_ids.insert(p.id_patch);
45 }
46 }
47
48 return out_ids;
49}
50
52 std::unordered_set<u64> &patch_id_lst,
53 std::vector<u64> &to_send_idx,
54 std::vector<u64> &to_recv_idx) {
55
56 local.clear();
57
58 for (u64 i = 0; i < global.size(); i++) {
59 const shamrock::patch::Patch &p = global[i];
60
61 bool was_owned = (patch_id_lst.find(p.id_patch) != patch_id_lst.end());
62
63 // TODO add check node_owner_id valid
64 if (i32(p.node_owner_id) == shamcomm::world_rank()) {
65 local.push_back(p);
66
67 if (!was_owned) {
68 to_recv_idx.push_back(i);
69 patch_id_lst.insert(p.id_patch);
70 }
71 } else {
72 if (was_owned) {
73 to_send_idx.push_back(i);
74 patch_id_lst.erase(p.id_patch);
75 }
76 }
77 }
78}
79
81 StackEntry stack_loc{};
83
84 u64 idx = 0;
86 id_patch_to_global_idx[p.id_patch] = idx;
87 idx++;
88 }
89}
90
92 StackEntry stack_loc{};
94
95 u64 idx = 0;
97 id_patch_to_local_idx[p.id_patch] = idx;
98 idx++;
99 }
100}
101
103 StackEntry stack_loc{};
104 for (shamrock::patch::Patch &p : local) {
105 p.pack_node_index = u64_max;
106 }
107}
108
109std::tuple<u64, u64, u64, u64, u64, u64, u64, u64> SchedulerPatchList::split_patch(u64 id_patch) {
110
111 using namespace shamrock::patch;
112
113 Patch &p0 = global[id_patch_to_global_idx[id_patch]];
114
115 std::array<Patch, 8> splts = p0.get_split();
116
117 p0 = splts[0]; // override existing patch
118
119 splts[1].id_patch = _next_patch_id;
121 splts[2].id_patch = _next_patch_id;
123 splts[3].id_patch = _next_patch_id;
125 splts[4].id_patch = _next_patch_id;
127 splts[5].id_patch = _next_patch_id;
129 splts[6].id_patch = _next_patch_id;
131 splts[7].id_patch = _next_patch_id;
133
134 // TODO use emplace_back instead
135 u64 idx_p1 = global.size();
136 global.push_back(splts[1]);
137
138 u64 idx_p2 = idx_p1 + 1;
139 global.push_back(splts[2]);
140
141 u64 idx_p3 = idx_p2 + 1;
142 global.push_back(splts[3]);
143
144 u64 idx_p4 = idx_p3 + 1;
145 global.push_back(splts[4]);
146
147 u64 idx_p5 = idx_p4 + 1;
148 global.push_back(splts[5]);
149
150 u64 idx_p6 = idx_p5 + 1;
151 global.push_back(splts[6]);
152
153 u64 idx_p7 = idx_p6 + 1;
154 global.push_back(splts[7]);
155
156 return {
157 id_patch_to_global_idx[id_patch], idx_p1, idx_p2, idx_p3, idx_p4, idx_p5, idx_p6, idx_p7};
158}
159
161 u64 idx0, u64 idx1, u64 idx2, u64 idx3, u64 idx4, u64 idx5, u64 idx6, u64 idx7) {
162
163 using namespace shamrock::patch;
164
165 Patch p = Patch::merge_patch(
166 {global[idx0],
167 global[idx1],
168 global[idx2],
169 global[idx3],
170 global[idx4],
171 global[idx5],
172 global[idx6],
173 global[idx7]});
174
175 global[idx0] = p;
176 global[idx1].set_err_mode();
177 global[idx2].set_err_mode();
178 global[idx3].set_err_mode();
179 global[idx4].set_err_mode();
180 global[idx5].set_err_mode();
181 global[idx6].set_err_mode();
182 global[idx7].set_err_mode();
183}
184
185namespace shamrock::patch {
186
196 inline void to_json(nlohmann::json &j, const Patch &p) {
197
198 // u64 id_patch;
199 // u64 pack_node_index;
200 // u64 load_value;
201 // std::array<u64,dim> coord_min;
202 // std::array<u64,dim> coord_max;
203 // u32 node_owner_id;
204
205 j = nlohmann::json{
206 {"id_patch", p.id_patch},
207 {"pack_node_index", p.pack_node_index},
208 {"load_value", p.load_value},
209 {"coord_min", p.coord_min},
210 {"coord_max", p.coord_max},
211 {"node_owner_id", p.node_owner_id},
212 };
213 }
214
224 inline void from_json(const nlohmann::json &j, Patch &p) {
225 j.at("id_patch").get_to(p.id_patch);
226 j.at("pack_node_index").get_to(p.pack_node_index);
227 j.at("load_value").get_to(p.load_value);
228 j.at("coord_min").get_to(p.coord_min);
229 j.at("coord_max").get_to(p.coord_max);
230 j.at("node_owner_id").get_to(p.node_owner_id);
231 }
232
233} // namespace shamrock::patch
234
235void to_json(nlohmann::json &j, const SchedulerPatchList &p) {
236 j = nlohmann::json{
237 {"_next_patch_id", p._next_patch_id},
238 {"global", p.global},
239 //{"local", p.local}, // must be disabled to avoid differences between ranks
240 {"is_load_values_up_to_date", p.is_load_values_up_to_date},
241 };
242}
243
244void from_json(const nlohmann::json &j, SchedulerPatchList &p) {
245 j.at("_next_patch_id").get_to(p._next_patch_id);
246 j.at("global").get_to(p.global);
247 // j.at("local").get_to(p.local); // must be disabled to avoid differences between ranks
248 j.at("is_load_values_up_to_date").get_to(p.is_load_values_up_to_date);
249}
250
251// TODO move in a separate file
252std::vector<shamrock::patch::Patch> make_fake_patch_list(u32 total_dtcnt, u64 div_limit) {
253
254 using namespace shamrock::patch;
255
256 std::vector<Patch> plist;
257
258 std::mt19937 eng(0x1111);
259 std::uniform_real_distribution<f32> split_val(0, 1);
260
261 using namespace shamrock::scheduler;
262
263 plist.push_back(
264 Patch{
265 .id_patch = 0,
266 .pack_node_index = u64_max,
267 .load_value = total_dtcnt,
268 .coord_min = {0, 0, 0},
269 .coord_max
273 .node_owner_id = 0,
274 });
275
276 bool listchanged = true;
277
278 u64 id_cnt = 0;
279 while (listchanged) {
280 listchanged = false;
281
282 std::vector<Patch> to_add;
283
284 for (Patch &p : plist) {
285 if (p.load_value > div_limit) {
286
287 /*
288 std::cout << "splitting : ( " <<
289 "[" << p.x_min << "," << p.x_max << "] " <<
290 "[" << p.y_min << "," << p.y_max << "] " <<
291 "[" << p.z_min << "," << p.z_max << "] " <<
292 " ) " << p.load_value << std::endl;
293 */
294
295 u64 min_x = p.coord_min[0];
296 u64 min_y = p.coord_min[1];
297 u64 min_z = p.coord_min[2];
298
299 u64 split_x = (((p.coord_max[0] - p.coord_min[0]) + 1) / 2) - 1 + min_x;
300 u64 split_y = (((p.coord_max[1] - p.coord_min[1]) + 1) / 2) - 1 + min_y;
301 u64 split_z = (((p.coord_max[2] - p.coord_min[2]) + 1) / 2) - 1 + min_z;
302
303 u64 max_x = p.coord_max[0];
304 u64 max_y = p.coord_max[1];
305 u64 max_z = p.coord_max[2];
306
307 u32 qte_m = split_val(eng) * p.load_value;
308 u32 qte_p = p.load_value - qte_m;
309
310 u32 qte_mm = split_val(eng) * qte_m;
311 u32 qte_mp = qte_m - qte_mm;
312
313 u32 qte_pm = split_val(eng) * qte_p;
314 u32 qte_pp = qte_p - qte_pm;
315
316 u32 qte_mmm = split_val(eng) * qte_mm;
317 u32 qte_mmp = qte_mm - qte_mmm;
318
319 u32 qte_mpm = split_val(eng) * qte_mp;
320 u32 qte_mpp = qte_mp - qte_mpm;
321
322 u32 qte_pmm = split_val(eng) * qte_pm;
323 u32 qte_pmp = qte_pm - qte_pmm;
324
325 u32 qte_ppm = split_val(eng) * qte_pp;
326 u32 qte_ppp = qte_pp - qte_ppm;
327
328 Patch child_mmm = Patch{
329 .id_patch = id_cnt,
330 .pack_node_index = u64_max,
331 .load_value = qte_mmm,
332 .coord_min = {min_x, min_y, min_z},
333 .coord_max = {split_x, split_y, split_z},
334 .node_owner_id = 0,
335 };
336 id_cnt++;
337
338 Patch child_mmp = Patch{
339 .id_patch = id_cnt,
340 .pack_node_index = u64_max,
341 .load_value = qte_mmp,
342 .coord_min = {min_x, min_y, split_z + 1},
343 .coord_max = {split_x, split_y, max_z},
344 .node_owner_id = 0,
345 };
346 id_cnt++;
347
348 Patch child_mpm = Patch{
349 .id_patch = id_cnt,
350 .pack_node_index = u64_max,
351 .load_value = qte_mpm,
352 .coord_min = {min_x, split_y + 1, min_z},
353 .coord_max = {split_x, max_y, split_z},
354 .node_owner_id = 0,
355 };
356 id_cnt++;
357
358 Patch child_mpp = Patch{
359 .id_patch = id_cnt,
360 .pack_node_index = u64_max,
361 .load_value = qte_mpp,
362 .coord_min = {min_x, split_y + 1, split_z + 1},
363 .coord_max = {split_x, max_y, max_z},
364 .node_owner_id = 0,
365 };
366 id_cnt++;
367
368 Patch child_pmm = Patch{
369 .id_patch = id_cnt,
370 .pack_node_index = u64_max,
371 .load_value = qte_pmm,
372 .coord_min = {split_x + 1, min_y, min_z},
373 .coord_max = {max_x, split_y, split_z},
374 .node_owner_id = 0,
375 };
376 id_cnt++;
377
378 Patch child_pmp = Patch{
379 .id_patch = id_cnt,
380 .pack_node_index = u64_max,
381 .load_value = qte_pmp,
382 .coord_min = {split_x + 1, min_y, split_z + 1},
383 .coord_max = {max_x, split_y, max_z},
384 .node_owner_id = 0,
385 };
386 id_cnt++;
387
388 Patch child_ppm = Patch{
389 .id_patch = id_cnt,
390 .pack_node_index = u64_max,
391 .load_value = qte_ppm,
392 .coord_min = {split_x + 1, split_y + 1, min_z},
393 .coord_max = {max_x, max_y, split_z},
394 .node_owner_id = 0,
395 };
396 id_cnt++;
397
398 Patch child_ppp = Patch{
399 .id_patch = id_cnt,
400 .pack_node_index = u64_max,
401 .load_value = qte_ppp,
402 .coord_min = {split_x + 1, split_y + 1, split_z + 1},
403 .coord_max = {max_x, max_y, max_z},
404 .node_owner_id = 0,
405 };
406 id_cnt++;
407
408 p = child_mmm;
409 to_add.push_back(child_mmp);
410 to_add.push_back(child_mpm);
411 to_add.push_back(child_mpp);
412 to_add.push_back(child_pmm);
413 to_add.push_back(child_pmp);
414 to_add.push_back(child_ppm);
415 to_add.push_back(child_ppp);
416 }
417 }
418
419 if (!to_add.empty()) {
420 listchanged = true;
421
422 plist.insert(plist.end(), to_add.begin(), to_add.end());
423 }
424
425 /*
426 for(Patch & p : plist){
427 std::cout << "( " <<
428 "[" << p.x_min << "," << p.x_max << "] " <<
429 "[" << p.y_min << "," << p.y_max << "] " <<
430 "[" << p.z_min << "," << p.z_max << "] " <<
431 " ) " << p.load_value << std::endl;
432 }
433
434 std::cout << "----- end cycle -----" << std::endl;
435 */
436 }
437
438 return plist;
439}
function to run load balancing with the hilbert curve
void from_json(const nlohmann::json &j, PatchDataLayerLayout &p)
Deserialize a PatchDataLayerLayout object from a JSON object.
void to_json(nlohmann::json &j, const PatchDataLayerLayout &p)
Serialize a PatchDataLayerLayout object to a JSON object.
Header file for the patch struct and related function.
std::uint32_t u32
32 bit unsigned integer
std::uint64_t u64
64 bit unsigned integer
std::int32_t i32
32 bit integer
Handle the patch list of the mpi scheduler.
std::vector< shamrock::patch::Patch > local
contain the list of patch owned by the current node
void reset_local_pack_index()
reset Patch's pack index value
std::unordered_map< u64, u64 > id_patch_to_local_idx
id_patch_to_local_idx[patch_id] = index in local patch list
std::vector< shamrock::patch::Patch > global
contain the list of all patches in the simulation
void build_global()
rebuild global from the local list of each tables
void build_local_differantial(std::unordered_set< u64 > &patch_id_lst, std::vector< u64 > &to_send_idx, std::vector< u64 > &to_recv_idx)
Build the local patch list and create a differential of patches to send / recv since last time.
u64 _next_patch_id
The next available patch id.
std::tuple< u64, u64, u64, u64, u64, u64, u64, u64 > split_patch(u64 id_patch)
split the Patch having id_patch as id and return the index of the 8 subpatches in the global vector
std::unordered_set< u64 > build_local()
select owned patches owned by the node to rebuild local
std::unordered_map< u64, u64 > id_patch_to_global_idx
id_patch_to_global_idx[patch_id] = index in global patch list
void merge_patch(u64 idx0, u64 idx1, u64 idx2, u64 idx3, u64 idx4, u64 idx5, u64 idx6, u64 idx7)
merge the 8 given patches index in the global vector
void build_local_idx_map()
recompute id_patch_to_local_idx
void build_global_idx_map()
recompute id_patch_to_global_idx
static constexpr u64 max_box_sz
maximal value along an axis for the patch coordinate
std::vector< int > vector_allgatherv(const std::vector< T > &send_vec, const MPI_Datatype &send_type, std::vector< T > &recv_vec, const MPI_Datatype &recv_type, const MPI_Comm comm)
allgatherv on vector with size query (size querying variant of vector_allgatherv_ks) //TODO add fault...
Definition exchanges.hpp:98
i32 world_rank()
Gives the rank of the current process in the MPI communicator.
Definition worldInfo.cpp:40
constexpr u64 u64_max
u64 max value
void to_json(nlohmann::json &j, const SchedulerPatchList &p)
Serializes a SchedulerPatchList object to a JSON object.
std::vector< shamrock::patch::Patch > make_fake_patch_list(u32 total_dtcnt, u64 div_limit)
generate a fake patch list corresponding to a tree structure
void from_json(const nlohmann::json &j, SchedulerPatchList &p)
Deserializes a JSON object into a SchedulerPatchList object.
Class to handle the patch list of the mpi scheduler.
This file contains the definition for the stacktrace related functionality.
shambase::details::BasicStackEntry StackEntry
Alias for shambase::details::BasicStackEntry.
Patch object that contain generic patch information.
Definition Patch.hpp:33