Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
RadixTree.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
16#include "shambase/floats.hpp"
17#include "shambase/integer.hpp"
18#include "shamalgs/memory.hpp"
24#include <tuple>
25#include <vector>
26
27template<class u_morton, class vec3>
28RadixTree<u_morton, vec3>::RadixTree(
29 sycl::queue &queue,
30 std::tuple<vec3, vec3> treebox,
31 sycl::buffer<vec3> &pos_buf,
32 u32 cnt_obj,
33 u32 reduc_level) {
34 if (cnt_obj > i32_max - 1) {
36 "number of element in patch above i32_max-1");
37 }
38
39 shamlog_debug_sycl_ln("RadixTree", "box dim :", std::get<0>(treebox), std::get<1>(treebox));
40
41 bounding_box = treebox;
42
43 tree_morton_codes.build(queue, shammath::CoordRange<vec3>{treebox}, cnt_obj, pos_buf);
44
45 bool one_cell_mode;
46
47 tree_reduced_morton_codes.build(
48 queue, tree_morton_codes.obj_cnt, reduc_level, tree_morton_codes, one_cell_mode);
49
50 if (!one_cell_mode) {
51 tree_struct.build(
52 queue,
53 tree_reduced_morton_codes.tree_leaf_count - 1,
54 *tree_reduced_morton_codes.buf_tree_morton);
55 } else {
56 tree_struct.build_one_cell_mode();
57 }
58}
59
60template<class u_morton, class vec3>
61RadixTree<u_morton, vec3>::RadixTree(
62 sycl::queue &queue,
63 std::tuple<vec3, vec3> treebox,
64 const std::unique_ptr<sycl::buffer<vec3>> &pos_buf,
65 u32 cnt_obj,
66 u32 reduc_level)
67 : RadixTree(queue, treebox, shambase::get_check_ref(pos_buf), cnt_obj, reduc_level) {}
68
69template<class u_morton, class Tvec>
70RadixTree<u_morton, Tvec>::RadixTree(
71 sham::DeviceScheduler_ptr dev_sched,
72 std::tuple<Tvec, Tvec> treebox,
74 u32 cnt_obj,
75 u32 reduc_level) {
76
77 sycl::queue &queue = dev_sched->get_queue().q;
78
79 if (cnt_obj > i32_max - 1) {
81 "number of element in patch above i32_max-1");
82 }
83
84 shamlog_debug_sycl_ln("RadixTree", "box dim :", std::get<0>(treebox), std::get<1>(treebox));
85
86 bounding_box = treebox;
87
88 tree_morton_codes.build(dev_sched, shammath::CoordRange<Tvec>{treebox}, cnt_obj, pos_buf);
89
90 bool one_cell_mode;
91
92 tree_reduced_morton_codes.build(
93 queue, tree_morton_codes.obj_cnt, reduc_level, tree_morton_codes, one_cell_mode);
94
95 if (!one_cell_mode) {
96 tree_struct.build(
97 queue,
98 tree_reduced_morton_codes.tree_leaf_count - 1,
99 *tree_reduced_morton_codes.buf_tree_morton);
100 } else {
101 tree_struct.build_one_cell_mode();
102 }
103}
104
105template<class u_morton, class vec3>
106void RadixTree<u_morton, vec3>::serialize(shamalgs::SerializeHelper &serializer) {
107 StackEntry stack_loc{};
108
109 serializer.write(std::get<0>(bounding_box));
110 serializer.write(std::get<1>(bounding_box));
111 tree_morton_codes.serialize(serializer);
112 tree_reduced_morton_codes.serialize(serializer);
113 tree_struct.serialize(serializer);
114 tree_cell_ranges.serialize(serializer);
115}
116
117template<class u_morton, class pos_t>
118shamalgs::SerializeSize RadixTree<u_morton, pos_t>::serialize_byte_size() {
120 return H::serialize_byte_size<pos_t>() * 2 + tree_morton_codes.serialize_byte_size()
121 + tree_reduced_morton_codes.serialize_byte_size() + tree_struct.serialize_byte_size()
122 + tree_cell_ranges.serialize_byte_size();
123}
124
125template<class u_morton, class pos_t>
126RadixTree<u_morton, pos_t> RadixTree<u_morton, pos_t>::deserialize(
127 shamalgs::SerializeHelper &serializer) {
128 StackEntry stack_loc{};
129
130 RadixTree ret;
131
132 serializer.load(std::get<0>(ret.bounding_box));
133 serializer.load(std::get<1>(ret.bounding_box));
134
135 using namespace shamrock::tree;
136
137 ret.tree_morton_codes = TreeMortonCodes<u_morton>::deserialize(serializer);
138 ret.tree_reduced_morton_codes = TreeReducedMortonCodes<u_morton>::deserialize(serializer);
139 ret.tree_struct = TreeStructure<u_morton>::deserialize(serializer);
140 ret.tree_cell_ranges = TreeCellRanges<u_morton, pos_t>::deserialize(serializer);
141
142 return ret;
143}
144
145template<class u_morton, class vec3>
146void RadixTree<u_morton, vec3>::compute_cell_ibounding_box(sycl::queue &queue) {
147 StackEntry stack_loc{};
148 tree_cell_ranges.build1(queue, tree_reduced_morton_codes, tree_struct);
149}
150
151template<class morton_t, class pos_t>
152void RadixTree<morton_t, pos_t>::convert_bounding_box(sycl::queue &queue) {
153 StackEntry stack_loc{};
154 u32 total_count = tree_struct.internal_cell_count + tree_reduced_morton_codes.tree_leaf_count;
155 tree_cell_ranges.build2(queue, total_count, bounding_box);
156}
157
158template<class u_morton, class vec>
159auto RadixTree<u_morton, vec>::compute_int_boxes(
160 sycl::queue &queue, sham::DeviceBuffer<coord_t> &int_rad_buf, coord_t tolerance)
162
163 shamlog_debug_sycl_ln("RadixTree", "compute int boxes");
164
165 auto buf_cell_interact_rad = RadixTreeField<coord_t>::make_empty(
166 1, tree_struct.internal_cell_count + tree_reduced_morton_codes.tree_leaf_count);
167 sycl::range<1> range_leaf_cell{tree_reduced_morton_codes.tree_leaf_count};
168
169 auto &buf_cell_int_rad_buf = buf_cell_interact_rad.radix_tree_field_buf;
170
171 sham::DeviceQueue q = shamsys::instance::get_compute_scheduler().get_queue();
172 sham::EventList depends_list;
173
174 auto h = int_rad_buf.get_read_access(depends_list);
175
176 auto e = q.submit(depends_list, [&](sycl::handler &cgh) {
177 u32 offset_leaf = tree_struct.internal_cell_count;
178
179 auto h_max_cell
180 = buf_cell_int_rad_buf->template get_access<sycl::access::mode::discard_write>(cgh);
181
182 auto cell_particle_ids = tree_reduced_morton_codes.buf_reduc_index_map
183 ->template get_access<sycl::access::mode::read>(cgh);
184 auto particle_index_map = tree_morton_codes.buf_particle_index_map
185 ->template get_access<sycl::access::mode::read>(cgh);
186
187 coord_t tol = tolerance;
188
189 cgh.parallel_for(range_leaf_cell, [=](sycl::item<1> item) {
190 u32 gid = (u32) item.get_id(0);
191
192 u32 min_ids = cell_particle_ids[gid];
193 u32 max_ids = cell_particle_ids[gid + 1];
194 f32 h_tmp = 0;
195
196 for (unsigned int id_s = min_ids; id_s < max_ids; id_s++) {
197
198 f32 h_a = h[particle_index_map[id_s]] * tol;
199 h_tmp = (h_tmp > h_a ? h_tmp : h_a);
200 }
201
202 h_max_cell[offset_leaf + gid] = h_tmp;
203 });
204 });
205
206 int_rad_buf.complete_event_state(e);
207
208#if false
209 // debug code to track the DPCPP + prime number worker issue
210 {
211
212 //172827
213 //86413
214 //<<<(43207,1,1),(2,1,1)>>>
215 //gid = 86412
216
217 shamalgs::memory::print_buf(*tree_struct.buf_rchild_id, tree_struct.internal_cell_count, 16, "{} ");
218 shamalgs::memory::print_buf(*tree_struct.buf_lchild_id, tree_struct.internal_cell_count, 16, "{} ");
219 shamalgs::memory::print_buf(*tree_struct.buf_rchild_flag, tree_struct.internal_cell_count, 16, "{} ");
220 shamalgs::memory::print_buf(*tree_struct.buf_lchild_flag, tree_struct.internal_cell_count, 16, "{} ");
221
222
223 sycl::host_accessor rchild_id {*tree_struct.buf_rchild_id ,sycl::read_only};
224 sycl::host_accessor lchild_id {*tree_struct.buf_lchild_id ,sycl::read_only};
225 sycl::host_accessor rchild_flag {*tree_struct.buf_rchild_flag,sycl::read_only};
226 sycl::host_accessor lchild_flag {*tree_struct.buf_lchild_flag,sycl::read_only};
227
228 u32 gid = 86412;
229 u32 lid_0 = lchild_id[gid];
230 u32 rid_0 = rchild_id[gid];
231 u32 lfl_0 = lchild_flag[gid];
232 u32 rfl_0 = rchild_flag[gid];
233 u32 offset_leaf = tree_struct.internal_cell_count;
234 u32 lid = lchild_id[gid] + offset_leaf * lchild_flag[gid];
235 u32 rid = rchild_id[gid] + offset_leaf * rchild_flag[gid];
236
237 logger::raw_ln("gid",gid);
238 logger::raw_ln("lid_0",lid_0);
239 logger::raw_ln("rid_0",rid_0);
240 logger::raw_ln("lfl_0",lfl_0);
241 logger::raw_ln("rfl_0",rfl_0);
242 logger::raw_ln("offset_leaf",offset_leaf);
243 logger::raw_ln("lid",lid);
244 logger::raw_ln("rid",rid);
245 logger::raw_ln("sz =", buf_cell_int_rad_buf->size());
246 logger::raw_ln("internal_cell_count =", tree_struct.internal_cell_count);
247 logger::raw_ln("tree_leaf_count =", tree_reduced_morton_codes.tree_leaf_count);
248 }
249#endif
250
251 sycl::range<1> range_tree{tree_struct.internal_cell_count};
252
253 for (u32 i = 0; i < tree_depth; i++) {
254 queue.submit([&](sycl::handler &cgh) {
255 u32 offset_leaf = tree_struct.internal_cell_count;
256
257 sycl::accessor h_max_cell{*buf_cell_int_rad_buf, cgh, sycl::read_write};
258
259 sycl::accessor rchild_id{*tree_struct.buf_rchild_id, cgh, sycl::read_only};
260 sycl::accessor lchild_id{*tree_struct.buf_lchild_id, cgh, sycl::read_only};
261 sycl::accessor rchild_flag{*tree_struct.buf_rchild_flag, cgh, sycl::read_only};
262 sycl::accessor lchild_flag{*tree_struct.buf_lchild_flag, cgh, sycl::read_only};
263
264 u32 len = tree_struct.internal_cell_count;
265 constexpr u32 group_size = 64;
266 u32 max_len = len;
267 u32 group_cnt = shambase::group_count(len, group_size);
268 u32 corrected_len = group_cnt * group_size;
269
270 cgh.parallel_for(
271 sycl::nd_range<1>{corrected_len, group_size}, [=](sycl::nd_item<1> id) {
272 u32 local_id = id.get_local_id(0);
273 u32 group_tile_id = id.get_group_linear_id();
274 u32 gid = group_tile_id * group_size + local_id;
275
276 if (gid >= max_len)
277 return;
278
279 u32 lid = lchild_id[gid] + offset_leaf * lchild_flag[gid];
280 u32 rid = rchild_id[gid] + offset_leaf * rchild_flag[gid];
281
282 coord_t h_l = h_max_cell[lid];
283 coord_t h_r = h_max_cell[rid];
284
285 h_max_cell[gid] = (h_r > h_l ? h_r : h_l);
286 });
287 });
288 }
289
290 {
291 u32 int_rad_cnt
292 = tree_struct.internal_cell_count + tree_reduced_morton_codes.tree_leaf_count;
293
294 sham::DeviceBuffer<coord_t> int_rad_dev_buf(
295 *buf_cell_int_rad_buf, int_rad_cnt, shamsys::instance::get_compute_scheduler_ptr());
296
297 if (shamalgs::reduction::has_nan(int_rad_dev_buf, int_rad_cnt)) {
299 *buf_cell_int_rad_buf,
300 tree_struct.internal_cell_count + tree_reduced_morton_codes.tree_leaf_count,
301 8,
302 "{} ");
304 "the structure of the tree as issue in ids");
305 }
306 }
307
308 return std::move(buf_cell_interact_rad);
309}
310
311template<class T>
312std::string print_member(const T &a);
313
314template<>
315std::string print_member(const u8 &a) {
316 return sham::format_printf("%d", u32(a));
317}
318
319template<>
320std::string print_member(const u32 &a) {
321 return sham::format_printf("%d", a);
322}
323
324template<class u_morton, class vec3>
325template<class T>
326void RadixTree<u_morton, vec3>::print_tree_field(sycl::buffer<T> &buf_field) {
327
328 sycl::host_accessor acc{buf_field, sycl::read_only};
329
330 u32 total_count = tree_struct.internal_cell_count + tree_reduced_morton_codes.tree_leaf_count;
331
332 u32 offset_leaf = tree_struct.internal_cell_count;
333
334 sycl::host_accessor rchild_id{*tree_struct.buf_rchild_id};
335 sycl::host_accessor lchild_id{*tree_struct.buf_lchild_id};
336 sycl::host_accessor rchild_flag{*tree_struct.buf_rchild_flag};
337 sycl::host_accessor lchild_flag{*tree_struct.buf_lchild_flag};
338
339 // start allow utf-8
340 auto printer = [&]() {
341 auto get_print_step
342 = [&](u32 gid, std::string prefix, bool is_left, auto &step_ref) -> std::string {
343 std::string ret_val = "";
344
345 if (!is_left) {
346 ret_val += prefix;
347 }
348
349 std::string val = " (" + print_member(acc[gid]) + ") ";
350 std::string val_empt = std::string(val.size(), ' ');
351
352 ret_val += (is_left ? "╦══" : "╚══");
353 ret_val += val;
354
355 if (gid < offset_leaf) {
356 u32 lid = lchild_id[gid] + offset_leaf * lchild_flag[gid];
357 u32 rid = rchild_id[gid] + offset_leaf * rchild_flag[gid];
358
359 ret_val += step_ref(
360 lid, prefix + (is_left ? "║ " + val_empt : " " + val_empt), true, step_ref);
361 ret_val += step_ref(
362 rid, prefix + (is_left ? "║ " + val_empt : " " + val_empt), false, step_ref);
363 } else {
364 ret_val += "\n";
365 }
366
367 return ret_val;
368 };
369
370 logger::raw_ln(get_print_step(0, "", false, get_print_step));
371 };
372 // end allow utf-8
373
374 printer();
375}
376
377template void RadixTree<u32, f64_3>::print_tree_field(sycl::buffer<u32> &buf_field);
378template void RadixTree<u32, f32_3>::print_tree_field(sycl::buffer<u32> &buf_field);
379template void RadixTree<u64, f64_3>::print_tree_field(sycl::buffer<u32> &buf_field);
380template void RadixTree<u64, f32_3>::print_tree_field(sycl::buffer<u32> &buf_field);
381
382template void RadixTree<u32, u32_3>::print_tree_field(sycl::buffer<u32> &buf_field);
383template void RadixTree<u32, u64_3>::print_tree_field(sycl::buffer<u32> &buf_field);
384template void RadixTree<u64, u32_3>::print_tree_field(sycl::buffer<u32> &buf_field);
385template void RadixTree<u64, u64_3>::print_tree_field(sycl::buffer<u32> &buf_field);
386template void RadixTree<u64, i64_3>::print_tree_field(sycl::buffer<u32> &buf_field);
387
388template<class u_morton, class vec3>
389typename RadixTree<u_morton, vec3>::CuttedTree RadixTree<u_morton, vec3>::cut_tree(
390 sycl::queue &queue, sycl::buffer<u8> &valid_node) {
391
392 u32 total_count = tree_struct.internal_cell_count + tree_reduced_morton_codes.tree_leaf_count;
393 sycl::range<1> range_tree{total_count};
394
395 {
396
397 // flag 1 valid
398 // flag 0 to be deleted
399 // flag 2 anything below should be deleted (2 if initialy 0 & parent = 1)
400 // basically 2 is le thing that would end up in the excluded lambda part
401
402 { // cascade zeros down the tree
403
404 sycl::buffer<u8> valid_node_new = sycl::buffer<u8>(total_count);
405
406 for (u32 it = 0; it < tree_depth; it++) {
407
408 shamlog_debug_sycl_ln("Radixtree", "cascading zeros step : ", it);
409 queue.submit([&](sycl::handler &cgh) {
410 sycl::accessor acc_valid_node_old{valid_node, cgh, sycl::read_only};
411 sycl::accessor acc_valid_node_new{
412 valid_node_new, cgh, sycl::write_only, sycl::no_init};
413
414 sycl::accessor acc_lchild_id{*tree_struct.buf_lchild_id, cgh, sycl::read_only};
415 sycl::accessor acc_rchild_id{*tree_struct.buf_rchild_id, cgh, sycl::read_only};
416 sycl::accessor acc_lchild_flag{
417 *tree_struct.buf_lchild_flag, cgh, sycl::read_only};
418 sycl::accessor acc_rchild_flag{
419 *tree_struct.buf_rchild_flag, cgh, sycl::read_only};
420
421 u32 leaf_offset = tree_struct.internal_cell_count;
422
423 cgh.parallel_for(
424 sycl::range<1>(tree_struct.internal_cell_count), [=](sycl::item<1> item) {
425 u32 lid = acc_lchild_id[item] + leaf_offset * acc_lchild_flag[item];
426 u32 rid = acc_rchild_id[item] + leaf_offset * acc_rchild_flag[item];
427
428 u8 old_nid_falg = acc_valid_node_old[item];
429
430 if (item.get_linear_id() == 0) {
431 acc_valid_node_new[item] = old_nid_falg;
432 }
433
434 if (old_nid_falg == 0 || old_nid_falg == 2) {
435 acc_valid_node_new[lid] = 0;
436 acc_valid_node_new[rid] = 0;
437 } else {
438 u8 old_lid_falg = acc_valid_node_old[lid];
439 u8 old_rid_falg = acc_valid_node_old[rid];
440
441 if (old_lid_falg == 0) {
442 old_lid_falg = 2;
443 }
444 if (old_rid_falg == 0) {
445 old_rid_falg = 2;
446 }
447
448 acc_valid_node_new[lid] = old_lid_falg;
449 acc_valid_node_new[rid] = old_rid_falg;
450 }
451 });
452 });
453
454 std::swap(valid_node, valid_node_new);
455 }
456 }
457
458 //{
459 // shamlog_debug_sycl_ln("Radixtree", "valid_node_state");
460 // print_tree_field(valid_node);
461 // logger::raw_ln("");
462 //}
463
464 sycl::buffer<u8> valid_tree_morton(tree_reduced_morton_codes.tree_leaf_count);
465
466 auto print_valid_morton = [&] {
467 shamlog_debug_sycl_ln("Radixtree", "valid_tree_morton");
468
469 sycl::buffer<u32> print_map(total_count);
470
471 {
472
473 sycl::host_accessor acc{print_map};
474 sycl::host_accessor acc_leaf{valid_tree_morton};
475
476 for (u32 i = 0; i < tree_reduced_morton_codes.tree_leaf_count; i++) {
477 acc[i + tree_struct.internal_cell_count] = acc_leaf[i];
478 }
479
480 for (u32 i = 0; i < tree_struct.internal_cell_count; i++) {
481 acc[i] = acc_leaf[i];
482 }
483 }
484
485 print_tree_field(print_map);
486
487 logger::raw_ln("");
488 };
489
490 queue.submit([&](sycl::handler &cgh) {
491 sycl::accessor acc_valid_tree_morton{
492 valid_tree_morton, cgh, sycl::write_only, sycl::no_init};
493
494 sycl::accessor acc_valid_node{valid_node, cgh, sycl::read_only};
495
496 u32 leaf_offset = tree_struct.internal_cell_count;
497
498 cgh.parallel_for(
499 sycl::range<1>(tree_reduced_morton_codes.tree_leaf_count), [=](sycl::item<1> item) {
500 u8 leaf_val = acc_valid_node[item.get_linear_id() + leaf_offset];
501
502 if (item.get_linear_id() < leaf_offset) {
503 if (acc_valid_node[item] == 2) {
504 leaf_val = 2;
505 }
506 }
507
508 acc_valid_tree_morton[item] = leaf_val;
509 });
510 });
511
512 // print_valid_morton();
513
514 // generate the new tree
515
516 RadixTree ret;
517
518 ret.bounding_box = bounding_box;
519
520 std::vector<u32> extract_id;
521
522 {
523
524 std::vector<u_morton> new_buf_morton;
525 std::vector<u32> new_buf_particle_index_map;
526 std::vector<u32> new_reduc_index_map;
527
528 u32 leaf_offset = tree_struct.internal_cell_count;
529
530 sycl::host_accessor cell_index_map{
531 *tree_reduced_morton_codes.buf_reduc_index_map, sycl::read_only};
532 sycl::host_accessor particle_index_map{
533 *tree_morton_codes.buf_particle_index_map, sycl::read_only};
534
535 sycl::host_accessor acc_valid_tree_morton{valid_tree_morton, sycl::read_only};
536
537 sycl::host_accessor acc_morton{*tree_morton_codes.buf_morton, sycl::read_only};
538
539 u32 cnt = 0;
540
541 for (u32 i = 0; i < tree_reduced_morton_codes.tree_leaf_count; i++) {
542 if (acc_valid_tree_morton[i] != 0) {
543
544 {
545 // loop on particle indexes
546 uint min_ids = cell_index_map[i];
547 uint max_ids = cell_index_map[i + 1];
548
549 new_reduc_index_map.push_back(cnt);
550
551 for (unsigned int id_s = min_ids; id_s < max_ids; id_s++) {
552
553 // recover old index before morton sort
554 uint id_b = particle_index_map[id_s];
555
556 // iteration function
557 {
558 extract_id.push_back(id_b);
559 new_buf_morton.push_back(acc_morton[id_b]);
560 new_buf_particle_index_map.push_back(cnt);
561
562 cnt++;
563 }
564 }
565 }
566 }
567 }
568
569 new_reduc_index_map.push_back(cnt);
570
571 std::vector<u_morton> new_morton_tree;
572
573 {
574 sycl::host_accessor acc_tree_morton{*tree_reduced_morton_codes.buf_tree_morton};
575
576 sycl::host_accessor acc_valid_tree_morton{valid_tree_morton, sycl::read_only};
577
578 for (u32 i = 0; i < tree_reduced_morton_codes.tree_leaf_count; i++) {
579 if (acc_valid_tree_morton[i] != 0) {
580 new_morton_tree.push_back(acc_tree_morton[i]);
581 }
582 }
583 }
584
585 ret.tree_reduced_morton_codes.tree_leaf_count = new_morton_tree.size();
586 ret.tree_struct.internal_cell_count = ret.tree_reduced_morton_codes.tree_leaf_count - 1;
587
588 ret.tree_morton_codes.buf_morton
589 = std::make_unique<sycl::buffer<u_morton>>(new_buf_morton.size());
590 {
591 sycl::host_accessor acc{
592 *ret.tree_morton_codes.buf_morton, sycl::write_only, sycl::no_init};
593 for (u32 i = 0; i < new_buf_morton.size(); i++) {
594 acc[i] = new_buf_morton[i];
595 }
596 }
597
598 ret.tree_morton_codes.buf_particle_index_map
599 = std::make_unique<sycl::buffer<u32>>(new_buf_particle_index_map.size());
600 {
601 sycl::host_accessor acc{
602 *ret.tree_morton_codes.buf_particle_index_map, sycl::write_only, sycl::no_init};
603 for (u32 i = 0; i < new_buf_particle_index_map.size(); i++) {
604 acc[i] = new_buf_particle_index_map[i];
605 }
606 }
607
608 if (ret.tree_reduced_morton_codes.tree_leaf_count > 1) {
609
610 ret.tree_reduced_morton_codes.buf_reduc_index_map
611 = std::make_unique<sycl::buffer<u32>>(new_reduc_index_map.size());
612 {
613 sycl::host_accessor acc{
614 *ret.tree_reduced_morton_codes.buf_reduc_index_map,
615 sycl::write_only,
616 sycl::no_init};
617 for (u32 i = 0; i < new_reduc_index_map.size(); i++) {
618 acc[i] = new_reduc_index_map[i];
619 }
620 }
621
622 ret.tree_reduced_morton_codes.buf_tree_morton
623 = std::make_unique<sycl::buffer<u_morton>>(new_morton_tree.size());
624 {
625 sycl::host_accessor acc{
626 *ret.tree_reduced_morton_codes.buf_tree_morton,
627 sycl::write_only,
628 sycl::no_init};
629 for (u32 i = 0; i < new_morton_tree.size(); i++) {
630 acc[i] = new_morton_tree[i];
631 }
632 }
633
634 ret.tree_struct.build(
635 queue,
636 ret.tree_struct.internal_cell_count,
637 *ret.tree_reduced_morton_codes.buf_tree_morton);
638
639 } else {
640 throw ShamrockSyclException("not implemented");
641 }
642 }
643
644 ret.compute_cell_ibounding_box(queue);
645 ret.convert_bounding_box(queue);
646
647#if false
648 std::unique_ptr<sycl::buffer<u32>> new_node_id_to_old_naive = std::make_unique<sycl::buffer<u32>>(ret.tree_leaf_count + ret.tree_internal_count);
649
650 {
651 auto & new_node_id_to_old = new_node_id_to_old_naive;
652
653 //junk fill
654 {
655 sycl::host_accessor acc{* new_node_id_to_old, sycl::write_only, sycl::no_init};
656 for (u32 i = 0 ; i < new_node_id_to_old->size(); i++) {
657 acc[i] = u32_max;
658 }
659 }
660
661
662 sycl::host_accessor acc_new_node_id_to_old {*new_node_id_to_old,sycl::write_only, sycl::no_init};
663
664 sycl::host_accessor new_tree_acc_pos_min_cell{*ret.buf_pos_min_cell,sycl::read_only};
665 sycl::host_accessor new_tree_acc_pos_max_cell{*ret.buf_pos_max_cell,sycl::read_only};
666
667 sycl::host_accessor old_tree_acc_pos_min_cell{*buf_pos_min_cell,sycl::read_only};
668 sycl::host_accessor old_tree_acc_pos_max_cell{*buf_pos_max_cell,sycl::read_only};
669
670 for(u32 i = 0 ; i < ret.tree_leaf_count + ret.tree_internal_count; i++){
671
672 vec3i cur_pos_min_cell_a = new_tree_acc_pos_min_cell[i];
673 vec3i cur_pos_max_cell_a = new_tree_acc_pos_max_cell[i];
674
675 for(u32 j = 0 ; j < tree_leaf_count + tree_internal_count; j++){
676
677 vec3i cur_pos_min_cell_b = old_tree_acc_pos_min_cell[j];
678 vec3i cur_pos_max_cell_b = old_tree_acc_pos_max_cell[j];
679
680
681 auto is_same_box = [&]() -> bool {
682 return
683 (cur_pos_min_cell_a.x() == cur_pos_min_cell_b.x()) &&
684 (cur_pos_min_cell_a.y() == cur_pos_min_cell_b.y()) &&
685 (cur_pos_min_cell_a.z() == cur_pos_min_cell_b.z()) &&
686 (cur_pos_max_cell_a.x() == cur_pos_max_cell_b.x()) &&
687 (cur_pos_max_cell_a.y() == cur_pos_max_cell_b.y()) &&
688 (cur_pos_max_cell_a.z() == cur_pos_max_cell_b.z()) ;
689 };
690
691 if(is_same_box()){
692
693 u32 store_val = j;
694
695 logger::raw_ln("i ->",cur_pos_min_cell_a,cur_pos_max_cell_a , "| ptr ->",cur_pos_min_cell_b,cur_pos_max_cell_b);
696
697
698 if(store_val >= tree_internal_count){
699 store_val -= tree_internal_count;
700 }
701
702 acc_new_node_id_to_old[i] = store_val;
703
704 break;
705 }
706
707
708 }
709 }
710 }
711
712 ret.print_tree_field(*new_node_id_to_old_naive);
713 std::unique_ptr<sycl::buffer<u32>> new_node_id_to_old_v1 = std::make_unique<sycl::buffer<u32>>(ret.tree_leaf_count + ret.tree_internal_count);
714
715 {
716 auto & new_node_id_to_old = new_node_id_to_old_v1;
717
718 //junk fill
719 {
720 sycl::host_accessor acc{* new_node_id_to_old, sycl::write_only, sycl::no_init};
721 for (u32 i = 0 ; i < new_node_id_to_old->size(); i++) {
722 acc[i] = u32_max;
723 }
724 }
725
726
727 sycl::host_accessor acc_new_node_id_to_old {*new_node_id_to_old,sycl::write_only, sycl::no_init};
728
729 sycl::host_accessor new_tree_acc_pos_min_cell{*ret.buf_pos_min_cell,sycl::read_only};
730 sycl::host_accessor new_tree_acc_pos_max_cell{*ret.buf_pos_max_cell,sycl::read_only};
731
732 sycl::host_accessor old_tree_acc_pos_min_cell{*buf_pos_min_cell,sycl::read_only};
733 sycl::host_accessor old_tree_acc_pos_max_cell{*buf_pos_max_cell,sycl::read_only};
734
735 sycl::host_accessor old_tree_lchild_id {*buf_lchild_id ,sycl::read_only};
736 sycl::host_accessor old_tree_rchild_id {*buf_rchild_id ,sycl::read_only};
737 sycl::host_accessor old_tree_lchild_flag {*buf_lchild_flag,sycl::read_only};
738 sycl::host_accessor old_tree_rchild_flag {*buf_rchild_flag,sycl::read_only};
739
740 u32 old_tree_leaf_offset = tree_internal_count;
741
742
743 for(u32 i = 0 ; i < ret.tree_leaf_count + ret.tree_internal_count; i++){
744
745 //logger::raw_ln();
746
747 vec3i cur_pos_min_cell_a = new_tree_acc_pos_min_cell[i];
748 vec3i cur_pos_max_cell_a = new_tree_acc_pos_max_cell[i];
749
750 u32 cur_id = 0;
751 vec3i cur_pos_min_cell_b = old_tree_acc_pos_min_cell[cur_id];
752 vec3i cur_pos_max_cell_b = old_tree_acc_pos_max_cell[cur_id];
753
754 while(true){
755
756 //logger::raw_ln("i ->",cur_pos_min_cell_a,cur_pos_max_cell_a , "| ptr ->",cur_pos_min_cell_b,cur_pos_max_cell_b);
757
758 auto is_same_box = [&]() -> bool {
759 return
760 (cur_pos_min_cell_a.x() == cur_pos_min_cell_b.x()) &&
761 (cur_pos_min_cell_a.y() == cur_pos_min_cell_b.y()) &&
762 (cur_pos_min_cell_a.z() == cur_pos_min_cell_b.z()) &&
763 (cur_pos_max_cell_a.x() == cur_pos_max_cell_b.x()) &&
764 (cur_pos_max_cell_a.y() == cur_pos_max_cell_b.y()) &&
765 (cur_pos_max_cell_a.z() == cur_pos_max_cell_b.z()) ;
766 };
767
768 auto potential_cell = [&](vec3i other_min, vec3i other_max) -> bool {
769 return
770 (cur_pos_min_cell_a.x() >= other_min.x()) &&
771 (cur_pos_min_cell_a.y() >= other_min.y()) &&
772 (cur_pos_min_cell_a.z() >= other_min.z()) &&
773 (cur_pos_max_cell_a.x() <= other_max.x()) &&
774 (cur_pos_max_cell_a.y() <= other_max.y()) &&
775 (cur_pos_max_cell_a.z() <= other_max.z()) ;
776 };
777
778 if(is_same_box()){
779
780 //logger::raw_ln("id : ",i,"found ",cur_id);
781
782 u32 store_val = cur_id;
783
784 if(store_val >= tree_internal_count){
785 store_val -= tree_internal_count;
786 }
787
788 acc_new_node_id_to_old[i] = store_val;
789
790 break;
791 }
792
793
794 u32 lid = old_tree_lchild_id[cur_id] + old_tree_leaf_offset * old_tree_lchild_flag[cur_id];
795 u32 rid = old_tree_rchild_id[cur_id] + old_tree_leaf_offset * old_tree_rchild_flag[cur_id];
796
797 vec3i cur_pos_min_cell_bl = old_tree_acc_pos_min_cell[lid];
798 vec3i cur_pos_max_cell_bl = old_tree_acc_pos_max_cell[lid];
799
800 vec3i cur_pos_min_cell_br = old_tree_acc_pos_min_cell[rid];
801 vec3i cur_pos_max_cell_br = old_tree_acc_pos_max_cell[rid];
802
803 bool l_ok = potential_cell(cur_pos_min_cell_bl,cur_pos_max_cell_bl);
804 bool r_ok = potential_cell(cur_pos_min_cell_br,cur_pos_max_cell_br);
805
806 //logger::raw_ln("options l=",lid,cur_pos_min_cell_bl,cur_pos_max_cell_bl,l_ok);
807 //logger::raw_ln("options r=",rid,cur_pos_min_cell_br,cur_pos_max_cell_br,r_ok);
808
809 if(l_ok){
810
811 cur_pos_min_cell_b = cur_pos_min_cell_bl;
812 cur_pos_max_cell_b = cur_pos_max_cell_bl;
813
814 cur_id = lid;
815 //logger::raw_ln("id : ",i,"moving to ",cur_id);
816
817 }else if(r_ok){
818 cur_pos_min_cell_b = cur_pos_min_cell_br;
819 cur_pos_max_cell_b = cur_pos_max_cell_br;
820
821 cur_id = rid;
822 //logger::raw_ln("id : ",i,"moving to ",cur_id);
823
824 }else{
825 throw "";
826 }
827
828
829
830
831
832
833 }
834
835 }
836 }
837
838 ret.print_tree_field(*new_node_id_to_old_v1);
839
840#endif
841
842 std::unique_ptr<sycl::buffer<u32>> new_node_id_to_old_v2
843 = std::make_unique<sycl::buffer<u32>>(
844 ret.tree_reduced_morton_codes.tree_leaf_count
845 + ret.tree_struct.internal_cell_count);
846
847 {
848 auto &new_node_id_to_old = new_node_id_to_old_v2;
849
850 // junk fill
851 {
852 sycl::host_accessor acc{*new_node_id_to_old, sycl::write_only, sycl::no_init};
853 for (u32 i = 0; i < new_node_id_to_old->size(); i++) {
854 acc[i] = u32_max;
855 }
856 }
857
858 shamsys::instance::get_compute_queue().submit([&](sycl::handler &cgh) {
859 sycl::accessor acc_new_node_id_to_old{
860 *new_node_id_to_old, cgh, sycl::write_only, sycl::no_init};
861
862 sycl::accessor new_tree_acc_pos_min_cell{
863 *ret.tree_cell_ranges.buf_pos_min_cell, cgh, sycl::read_write};
864 sycl::accessor new_tree_acc_pos_max_cell{
865 *ret.tree_cell_ranges.buf_pos_max_cell, cgh, sycl::read_write};
866
867 sycl::accessor old_tree_acc_pos_min_cell{
868 *tree_cell_ranges.buf_pos_min_cell, cgh, sycl::read_only};
869 sycl::accessor old_tree_acc_pos_max_cell{
870 *tree_cell_ranges.buf_pos_max_cell, cgh, sycl::read_only};
871
872 sycl::accessor old_tree_lchild_id{*tree_struct.buf_lchild_id, cgh, sycl::read_only};
873 sycl::accessor old_tree_rchild_id{*tree_struct.buf_rchild_id, cgh, sycl::read_only};
874 sycl::accessor old_tree_lchild_flag{
875 *tree_struct.buf_lchild_flag, cgh, sycl::read_only};
876 sycl::accessor old_tree_rchild_flag{
877 *tree_struct.buf_rchild_flag, cgh, sycl::read_only};
878
879 u32 old_tree_leaf_offset = tree_struct.internal_cell_count;
880
881 sycl::range<1> range_node = sycl::range<1>{
882 ret.tree_reduced_morton_codes.tree_leaf_count
883 + ret.tree_struct.internal_cell_count};
884
885 // auto out = sycl::stream(128, 128, cgh);
886
887 cgh.parallel_for(range_node, [=](sycl::item<1> item) {
888 // logger::raw_ln("\n \n ----------------\n \nnode : ",item.get_id(0));
889
890 ipos_t cur_pos_min_cell_a = new_tree_acc_pos_min_cell[item];
891 ipos_t cur_pos_max_cell_a = new_tree_acc_pos_max_cell[item];
892
893 u32 cur_id = 0;
894 ipos_t cur_pos_min_cell_b = old_tree_acc_pos_min_cell[cur_id];
895 ipos_t cur_pos_max_cell_b = old_tree_acc_pos_max_cell[cur_id];
896
897 while (true) {
898
899 // logger::raw_ln("i ->",cur_pos_min_cell_a,cur_pos_max_cell_a , "| ptr
900 // ->",cur_pos_min_cell_b,cur_pos_max_cell_b);
901
902 auto is_same_box = [&]() -> bool {
903 return (cur_pos_min_cell_a.x() == cur_pos_min_cell_b.x())
904 && (cur_pos_min_cell_a.y() == cur_pos_min_cell_b.y())
905 && (cur_pos_min_cell_a.z() == cur_pos_min_cell_b.z())
906 && (cur_pos_max_cell_a.x() == cur_pos_max_cell_b.x())
907 && (cur_pos_max_cell_a.y() == cur_pos_max_cell_b.y())
908 && (cur_pos_max_cell_a.z() == cur_pos_max_cell_b.z());
909 };
910
911 auto potential_cell = [&](ipos_t other_min, ipos_t other_max) -> bool {
912 return (cur_pos_min_cell_a.x() >= other_min.x())
913 && (cur_pos_min_cell_a.y() >= other_min.y())
914 && (cur_pos_min_cell_a.z() >= other_min.z())
915 && (cur_pos_max_cell_a.x() <= other_max.x())
916 && (cur_pos_max_cell_a.y() <= other_max.y())
917 && (cur_pos_max_cell_a.z() <= other_max.z());
918 };
919
920 auto contain_cell = [&](ipos_t other_min, ipos_t other_max) -> bool {
921 return (cur_pos_min_cell_a.x() <= other_min.x())
922 && (cur_pos_min_cell_a.y() <= other_min.y())
923 && (cur_pos_min_cell_a.z() <= other_min.z())
924 && (cur_pos_max_cell_a.x() >= other_max.x())
925 && (cur_pos_max_cell_a.y() >= other_max.y())
926 && (cur_pos_max_cell_a.z() >= other_max.z());
927 };
928
929 if (is_same_box()) {
930
931 // logger::raw_ln("found ",cur_id);
932
933 u32 store_val = cur_id;
934
935 // if(store_val >= old_tree_leaf_offset){
936 // store_val -= old_tree_leaf_offset;
937 // }
938
939 acc_new_node_id_to_old[item] = store_val;
940
941 break;
942 }
943
944 u32 lid = old_tree_lchild_id[cur_id]
945 + old_tree_leaf_offset * old_tree_lchild_flag[cur_id];
946 u32 rid = old_tree_rchild_id[cur_id]
947 + old_tree_leaf_offset * old_tree_rchild_flag[cur_id];
948
949 ipos_t cur_pos_min_cell_bl = old_tree_acc_pos_min_cell[lid];
950 ipos_t cur_pos_max_cell_bl = old_tree_acc_pos_max_cell[lid];
951
952 ipos_t cur_pos_min_cell_br = old_tree_acc_pos_min_cell[rid];
953 ipos_t cur_pos_max_cell_br = old_tree_acc_pos_max_cell[rid];
954
955 bool l_ok = potential_cell(cur_pos_min_cell_bl, cur_pos_max_cell_bl);
956 bool r_ok = potential_cell(cur_pos_min_cell_br, cur_pos_max_cell_br);
957
958 // logger::raw_ln("options
959 // l=",lid,cur_pos_min_cell_bl,cur_pos_max_cell_bl,l_ok);
960 // logger::raw_ln("options
961 // r=",rid,cur_pos_min_cell_br,cur_pos_max_cell_br,r_ok);
962
963 if (l_ok) {
964
965 cur_pos_min_cell_b = cur_pos_min_cell_bl;
966 cur_pos_max_cell_b = cur_pos_max_cell_bl;
967
968 cur_id = lid;
969 // logger::raw_ln("moving to ",cur_id);
970
971 } else if (r_ok) {
972 cur_pos_min_cell_b = cur_pos_min_cell_br;
973 cur_pos_max_cell_b = cur_pos_max_cell_br;
974
975 cur_id = rid;
976 // logger::raw_ln("moving to ",cur_id);
977
978 } else {
979
980 // if nothing is neither the same or a super set of our cell it means
981 // that
982 // our cell is a superset of one of the child hence the following check
983 bool l_contain = contain_cell(cur_pos_min_cell_bl, cur_pos_max_cell_bl);
984 bool r_contain = contain_cell(cur_pos_min_cell_br, cur_pos_max_cell_br);
985
986 // logger::raw_ln("options
987 // l=",lid,cur_pos_min_cell_bl,cur_pos_max_cell_bl,l_contain);
988 // logger::raw_ln("options
989 // r=",rid,cur_pos_min_cell_br,cur_pos_max_cell_br,r_contain);
990
991 if (l_contain) {
992 // logger::raw_ln("found ",cur_id);
993
994 u32 store_val = cur_id;
995 acc_new_node_id_to_old[item] = store_val;
996
997 // TODO : check that no particules are outside of the bound when
998 // restricted by this line
999 new_tree_acc_pos_min_cell[item] = cur_pos_min_cell_bl;
1000 new_tree_acc_pos_max_cell[item] = cur_pos_max_cell_bl;
1001
1002 break;
1003 } else if (r_contain) {
1004 // logger::raw_ln("found ",cur_id);
1005
1006 u32 store_val = cur_id;
1007 acc_new_node_id_to_old[item] = store_val;
1008
1009 // TODO : check that no particules are outside of the bound when
1010 // restricted by this line
1011 new_tree_acc_pos_min_cell[item] = cur_pos_min_cell_br;
1012 new_tree_acc_pos_max_cell[item] = cur_pos_max_cell_br;
1013
1014 break;
1015 } else {
1016 // out << "[CRASH] Tree cut had a weird behavior during old cell
1017 // search : \n"; throw "";
1018
1019 u32 store_val = cur_id;
1020
1021 // if(store_val >= old_tree_leaf_offset){
1022 // store_val -= old_tree_leaf_offset;
1023 // }
1024
1025 acc_new_node_id_to_old[item] = store_val;
1026
1027 break;
1028 }
1029 }
1030 }
1031 });
1032 });
1033 }
1034
1035 // because we have updated the cell ranges in the tree cut
1036 shamrock::sfc::MortonKernels<u_morton, vec3, dim>::sycl_irange_to_range(
1037 queue,
1038 ret.tree_reduced_morton_codes.tree_leaf_count + ret.tree_struct.internal_cell_count,
1039 std::get<0>(ret.bounding_box),
1040 std::get<1>(ret.bounding_box),
1041 ret.tree_cell_ranges.buf_pos_min_cell,
1042 ret.tree_cell_ranges.buf_pos_max_cell,
1043 ret.tree_cell_ranges.buf_pos_min_cell_flt,
1044 ret.tree_cell_ranges.buf_pos_max_cell_flt);
1045
1046 // ret.print_tree_field(*new_node_id_to_old_v2);
1047
1048 shamlog_debug_ln(
1049 "TreeCutter",
1050 "tree cut cells:",
1051 tree_struct.internal_cell_count,
1052 "->",
1053 ret.tree_struct.internal_cell_count,
1054 "obj:",
1055 tree_morton_codes.obj_cnt,
1056 "->",
1057 extract_id.size());
1058
1059 return CuttedTree{
1060 std::move(ret),
1061 std::move(new_node_id_to_old_v2),
1062 std::make_unique<sycl::buffer<u32>>(shamalgs::memory::vector_to_buf(
1063 shamsys::instance::get_compute_queue(), std::move(extract_id)))};
1064 }
1065}
1066
1067template class RadixTree<u32, f32_3>;
1068template class RadixTree<u64, f32_3>;
1069
1070template class RadixTree<u32, f64_3>;
1071template class RadixTree<u64, f64_3>;
1072
1073template class RadixTree<u32, u32_3>;
1074template class RadixTree<u64, u32_3>;
1075
1076template class RadixTree<u32, u64_3>;
1077template class RadixTree<u64, u64_3>;
1078
1079template class RadixTree<u32, i64_3>;
1080template class RadixTree<u64, i64_3>;
constexpr const char * uint
Specific internal energy u.
Header file describing a Node Instance.
sycl::queue & get_compute_queue(u32 id=0)
Utility to build morton codes for the radix tree.
float f32
Alias for float.
std::uint8_t u8
8 bit unsigned integer
std::uint32_t u32
32 bit unsigned integer
The radix tree.
Definition RadixTree.hpp:50
A buffer allocated in USM (Unified Shared Memory).
A SYCL queue associated with a device and a context.
sycl::event submit(Fct &&fct)
Submits a kernel to the SYCL queue.
Class to manage a list of SYCL events.
Definition EventList.hpp:32
static TreeMortonCodes deserialize(shamalgs::SerializeHelper &serializer)
deserialize a TreeMortonCodes object Note : here since the initial buffer is a pow of 2 with traillin...
void print_buf(sycl::buffer< T > &buf, u32 len, u32 column_count, std::string_view fmt)
Print the content of a sycl::buffer.
Definition memory.hpp:181
namespace for basic c++ utilities
constexpr u32 group_count(u32 len, u32 group_size)
Calculates the number of groups based on the length and group size.
Definition integer.hpp:125
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:112
ExcptTypes make_except_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Create an exception with a message and a location.
constexpr u32 u32_max
u32 max value
constexpr i32 i32_max
i32 max value
main include file for memory algorithms
void raw_ln(Types... var2)
Prints a log message with multiple arguments followed by a newline.
Definition logs.hpp:89
shambase::details::BasicStackEntry StackEntry
Alias for shambase::details::BasicStackEntry.
header file to manage sycl