Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
PatchTree.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
23#include <nlohmann/json.hpp>
24#include <stdexcept>
25#include <vector>
26
27namespace shamrock::scheduler {
28 u64 PatchTree::insert_node(Node n) {
29 tree[next_id] = n;
30 next_id++;
31 return next_id - 1;
32 }
33
34 void PatchTree::remove_node(u64 id) { tree.erase(id); }
35
37
38 leaf_key.erase(id);
39
40 Node &curr = tree[id];
41
42 auto &tree_node = curr.tree_node;
43 if (tree_node.parent_nid != u64_max) {
44 parent_of_only_leaf_key.erase(tree_node.parent_nid);
45 tree[tree_node.parent_nid].tree_node.child_are_all_leafs = false;
46 }
47
48 tree_node.is_leaf = false;
49 tree_node.child_are_all_leafs = true;
50
51 std::array<Node, Node::split_count> splitted_node = curr.get_split_nodes(id);
52
53#pragma unroll
54 for (u32 i = 0; i < Node::split_count; i++) {
55 curr.tree_node.childs_nid[i] = insert_node(splitted_node[i]);
56 }
57
58 parent_of_only_leaf_key.insert(id);
59
60#pragma unroll
61 for (u32 i = 0; i < Node::split_count; i++) {
62 leaf_key.insert(curr.tree_node.childs_nid[i]);
63 }
64 }
65
67
68 Node &parent_node = tree[idparent];
69 auto &parent_tnode = parent_node.tree_node;
70
71 if (!parent_tnode.child_are_all_leafs) {
73 "node should be parent of only leafs");
74 }
75
76 leaf_key.erase(parent_tnode.childs_nid[0]);
77 leaf_key.erase(parent_tnode.childs_nid[1]);
78 leaf_key.erase(parent_tnode.childs_nid[2]);
79 leaf_key.erase(parent_tnode.childs_nid[3]);
80 leaf_key.erase(parent_tnode.childs_nid[4]);
81 leaf_key.erase(parent_tnode.childs_nid[5]);
82 leaf_key.erase(parent_tnode.childs_nid[6]);
83 leaf_key.erase(parent_tnode.childs_nid[7]);
84
85 remove_node(parent_tnode.childs_nid[0]);
86 remove_node(parent_tnode.childs_nid[1]);
87 remove_node(parent_tnode.childs_nid[2]);
88 remove_node(parent_tnode.childs_nid[3]);
89 remove_node(parent_tnode.childs_nid[4]);
90 remove_node(parent_tnode.childs_nid[5]);
91 remove_node(parent_tnode.childs_nid[6]);
92 remove_node(parent_tnode.childs_nid[7]);
93
94 parent_tnode.childs_nid[0] = u64_max;
95 parent_tnode.childs_nid[1] = u64_max;
96 parent_tnode.childs_nid[2] = u64_max;
97 parent_tnode.childs_nid[3] = u64_max;
98 parent_tnode.childs_nid[4] = u64_max;
99 parent_tnode.childs_nid[5] = u64_max;
100 parent_tnode.childs_nid[6] = u64_max;
101 parent_tnode.childs_nid[7] = u64_max;
102
103 leaf_key.insert(idparent);
104 parent_tnode.is_leaf = true;
105
106 parent_of_only_leaf_key.erase(idparent);
107 parent_tnode.child_are_all_leafs = false;
108
109 // check if parent of parent_tnode is parent of only leafs
110 if (parent_tnode.parent_nid != u64_max) {
111 bool only_leafs = true;
112
113 Node &parent_node = tree[parent_tnode.parent_nid];
114
115 for (u8 idc = 0; idc < 8; idc++) {
116 only_leafs = only_leafs && tree[parent_node.get_child_nid(idc)].is_leaf();
117 }
118
119 if (only_leafs) {
120 parent_node.tree_node.child_are_all_leafs = true;
121 parent_of_only_leaf_key.insert(parent_tnode.parent_nid);
122 }
123 }
124 }
125
126 void PatchTree::insert_root_node(u32 patch_id, patch::PatchCoord<3> coords) {
127 Node root;
128 root.patch_coord = coords;
129 root.tree_node.level = 0;
130 root.tree_node.parent_nid = u64_max;
131 root.tree_node.is_leaf = true;
132 root.tree_node.child_are_all_leafs = false;
133 root.linked_patchid = patch_id;
134
135 u64 root_id = insert_node(root);
136 leaf_key.insert(root_id);
137 roots_id.insert(root_id);
138 }
139
141 std::vector<shamrock::patch::Patch> &plist, u64 max_val_1axis) {
142
143 if (plist.size() > 1) {
144 Node root;
145 root.patch_coord.coord_max[0] = max_val_1axis;
146 root.patch_coord.coord_max[1] = max_val_1axis;
147 root.patch_coord.coord_max[2] = max_val_1axis;
148 root.patch_coord.coord_min[0] = 0;
149 root.patch_coord.coord_min[1] = 0;
150 root.patch_coord.coord_min[2] = 0;
151 root.tree_node.level = 0;
152 root.tree_node.parent_nid = u64_max;
153
154 u64 root_id = insert_node(root);
155 leaf_key.insert(root_id);
156 roots_id.insert(root_id);
157
158 std::vector<u64> complete_vec;
159 for (u64 i = 0; i < plist.size(); i++) {
160 complete_vec.push_back(i);
161 }
162
163 std::vector<std::tuple<u64, std::vector<u64>>> tree_vec(1);
164
165 tree_vec[0] = {root_id, complete_vec};
166
167 while (tree_vec.size() > 0) {
168 std::vector<std::tuple<u64, std::vector<u64>>> next_tree_vec;
169 for (auto &[idtree, idvec] : tree_vec) {
170
171 Node &ptn = tree[idtree];
172
173 split_node(idtree);
174
175 for (u8 child_id = 0; child_id < 8; child_id++) {
176
177 u64 ptnode_id = ptn.tree_node.childs_nid[child_id];
178 std::vector<u64> buf;
179
180 auto &curr = tree[ptnode_id].patch_coord;
181
182 for (u64 idxptch : idvec) {
183 shamrock::patch::Patch &p = plist[idxptch];
184
185 bool is_inside = BBAA::iscellb_inside_a<u32_3>(
186 {curr.coord_min[0], curr.coord_min[1], curr.coord_min[2]},
187 {curr.coord_max[0], curr.coord_max[1], curr.coord_max[2]},
188 {p.coord_min[0], p.coord_min[1], p.coord_min[2]},
189 {p.coord_max[0], p.coord_max[1], p.coord_max[2]});
190
191 if (is_inside) {
192 buf.push_back(idxptch);
193 }
194
195 /*
196 std::cout << " ( " <<
197 "[" << curr.x_min << "," << curr.x_max << "] " <<
198 "[" << curr.y_min << "," << curr.y_max << "] " <<
199 "[" << curr.z_min << "," << curr.z_max << "] " <<
200 " ) node : ( " <<
201 "[" << p.x_min << "," << p.x_max << "] " <<
202 "[" << p.y_min << "," << p.y_max << "] " <<
203 "[" << p.z_min << "," << p.z_max << "] " <<
204 " ) "<< is_inside;
205
206 if(is_inside){ std::cout << " -> push " << idxptch;}
207
208 std::cout << std::endl;
209 */
210 }
211
212 if (buf.size() == 1) {
213 // std::cout << "set linked id node " << buf[0] << " : " <<
214 // plist[buf[0]].id_patch << std::endl;
215 tree[ptnode_id].linked_patchid = plist[buf[0]].id_patch;
216 } else {
217 next_tree_vec.push_back({ptnode_id, buf});
218 }
219 }
220
221 } // std::cout << "----------------" << std::endl;
222
223 tree_vec = next_tree_vec;
224 }
225 } else if (plist.size() == 1) {
226
227 patch::PatchCoord patch_coord;
228 patch_coord.coord_max[0] = max_val_1axis;
229 patch_coord.coord_max[1] = max_val_1axis;
230 patch_coord.coord_max[2] = max_val_1axis;
231 patch_coord.coord_min[0] = 0;
232 patch_coord.coord_min[1] = 0;
233 patch_coord.coord_min[2] = 0;
234 insert_root_node(plist[0].id_patch, patch_coord);
235 }
236 }
237
238 void PatchTree::update_ptnode(
239 Node &n,
240 std::vector<shamrock::patch::Patch> &plist,
241 const std::unordered_map<u64, u64> &id_patch_to_global_idx) {
242
243 auto &tnode = n.tree_node;
244
245 if (n.linked_patchid != u64_max) {
246 n.load_value = 0;
247 n.load_value += plist[id_patch_to_global_idx.at(n.linked_patchid)].load_value;
248 } else if (tnode.childs_nid[0] != u64_max) {
249
250 bool has_err_val = false;
251
252 n.load_value = 0;
253 for (u8 idc = 0; idc < 8; idc++) {
254
255 if (tree[tnode.childs_nid[idc]].load_value == u64_max)
256 has_err_val = true;
257
258 n.load_value += tree[tnode.childs_nid[idc]].load_value;
259 }
260
261 if (has_err_val) {
262 n.load_value = u64_max;
263 }
264 }
265 }
266
267 // TODO add test value on root = sum all leaf
269 std::vector<shamrock::patch::Patch> &plist,
270 const std::unordered_map<u64, u64> &id_patch_to_global_idx) {
271
272 tree[0].load_value = u64_max;
273
274 while (tree[0].load_value == u64_max) {
275 for (auto &[key, ptnode] : tree) {
276 update_ptnode(ptnode, plist, id_patch_to_global_idx);
277 }
278 }
279 }
280
282 std::vector<shamrock::patch::Patch> &plist,
283 const std::unordered_map<u64, u64> &id_patch_to_global_idx) {
284 StackEntry stack_loc{};
285
286 for (u64 id_leaf : leaf_key) {
287 update_ptnode(tree[id_leaf], plist, id_patch_to_global_idx);
288 }
289
290 for (u64 id_leaf : parent_of_only_leaf_key) {
291 update_ptnode(tree[id_leaf], plist, id_patch_to_global_idx);
292 }
293 }
294
295 std::unordered_set<u64> PatchTree::get_split_request(u64 crit_load_split) {
296 StackEntry stack_loc{};
297 std::unordered_set<u64> rq;
298
299 for (u64 a : leaf_key) {
300 if (tree[a].load_value > crit_load_split) {
301 rq.insert(a);
302 }
303 }
304
305 return rq;
306 }
307
308 std::unordered_set<u64> PatchTree::get_merge_request(u64 crit_load_merge) {
309 StackEntry stack_loc{};
310 std::unordered_set<u64> rq;
311
312 for (u64 a : parent_of_only_leaf_key) {
313 if (tree[a].load_value < crit_load_merge) {
314 rq.insert(a);
315 }
316 }
317
318 return rq;
319 }
320
326 nlohmann::json PatchTree::serialize_patch_metadata() const {
327 // Serialized fields :
328 // - std::unordered_set<u64> roots_id;
329 // - std::unordered_map<u64, Node> tree;
330 // - std::unordered_set<u64> leaf_key;
331 // - std::unordered_set<u64> parent_of_only_leaf_key;
332
333 // Note it is not possible to serialize STL containers if this function is not marked const
334 return {
335 {"roots_id", roots_id},
336 {"tree", tree},
337 {"leaf_key", leaf_key},
338 {"parent_of_only_leaf_key", parent_of_only_leaf_key},
339 {"next_id", next_id}};
340 }
341
347 void PatchTree::load_json(const nlohmann::json &j) {
348
349 j.at("roots_id").get_to(roots_id);
350 j.at("tree").get_to(tree);
351 j.at("leaf_key").get_to(leaf_key);
352 j.at("parent_of_only_leaf_key").get_to(parent_of_only_leaf_key);
353 j.at("next_id").get_to(next_id);
354 }
355
362 void to_json(nlohmann::json &j, const PatchTree &p) { j = p.serialize_patch_metadata(); }
363
370 void from_json(const nlohmann::json &j, PatchTree &p) { p.load_json(j); }
371
372} // namespace shamrock::scheduler
Header file for the patch struct and related function.
std::uint8_t u8
8 bit unsigned integer
std::uint32_t u32
32 bit unsigned integer
std::uint64_t u64
64 bit unsigned integer
bool child_are_all_leafs
Store true if all childrens of this node are leafs.
std::array< u64, 8 > childs_nid
Array of childs node ids.
u32 level
Level of the tree node.
Node information in the patchtree + held patch info.
Patch Tree : Tree structure organisation for an abstract list of patches Nb : this tree is compatible...
Definition PatchTree.hpp:29
void load_json(const nlohmann::json &j)
Load the metadata of the patch tree from a JSON object.
std::unordered_set< u64 > roots_id
set of root nodes ids
Definition PatchTree.hpp:37
std::unordered_set< u64 > leaf_key
key of leaf nodes in tree
Definition PatchTree.hpp:49
std::unordered_set< u64 > get_merge_request(u64 crit_load_merge)
Get list of nodes id to merge.
void build_from_patchtable(std::vector< Patch > &plist, u64 max_val_1axis)
make tree from a patch table
nlohmann::json serialize_patch_metadata() const
Serialize the metadata of the patch tree.
std::unordered_set< u64 > get_split_request(u64 crit_load_split)
Get list of nodes id to split.
void update_values_node(std::vector< Patch > &plist, const std::unordered_map< u64, u64 > &id_patch_to_global_idx)
update value in nodes (tree reduction)
std::unordered_set< u64 > parent_of_only_leaf_key
key of nodes that have only leafs as child
Definition PatchTree.hpp:55
void partial_values_reduction(std::vector< Patch > &plist, const std::unordered_map< u64, u64 > &id_patch_to_global_idx)
update values in leafs and parent_of_only_leaf_key only
void merge_node_dm1(u64 idparent)
merge childs of idparent (id parent should have only leafs as childs)
Definition PatchTree.cpp:66
std::unordered_map< u64, Node > tree
store the tree using a map
Definition PatchTree.hpp:43
void split_node(u64 id)
split a leaf node
Definition PatchTree.cpp:36
This header file contains utility functions related to exception handling in the code.
void throw_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Throw an exception and append the source location to it.
constexpr u64 u64_max
u64 max value
This file contains the definition for the stacktrace related functionality.
Patch object that contain generic patch information.
Definition Patch.hpp:33