Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
dtt_reference.hpp
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
10#pragma once
11
19#include "shambackends/vec.hpp"
20#include "shamcomm/logs.hpp"
25
26namespace shamtree::details {
27
28 template<class Tmorton, class Tvec, u32 dim>
30
31 using Tscal = shambase::VecComponent<Tvec>;
32
34 using ObjItHostAcc = typename ObjItHost::acc;
35
36 inline static bool mac(shammath::AABB<Tvec> a, shammath::AABB<Tvec> b, Tscal theta_crit) {
37 return shamtree::details::mac(a, b, theta_crit);
38 }
39
41 template<bool allow_leaf_lowering>
42 inline static void dtt_recursive_internal(
43 u32 cell_a,
44 u32 cell_b,
45 const ObjItHostAcc &acc,
46 Tscal theta_crit,
47 std::vector<u32_2> &interact_m2l,
48 std::vector<u32_2> &interact_p2p) {
49
50 auto dtt_child_call = [&](u32 cell_a, u32 cell_b) {
51 dtt_recursive_internal<allow_leaf_lowering>(
52 cell_a, cell_b, acc, theta_crit, interact_m2l, interact_p2p);
53 };
54
55 auto &ttrav = acc.tree_traverser.tree_traverser;
56
57 Tvec aabb_min_a = acc.tree_traverser.aabb_min[cell_a];
58 Tvec aabb_max_a = acc.tree_traverser.aabb_max[cell_a];
59
60 Tvec aabb_min_b = acc.tree_traverser.aabb_min[cell_b];
61 Tvec aabb_max_b = acc.tree_traverser.aabb_max[cell_b];
62
63 shammath::AABB<Tvec> aabb_a = {aabb_min_a, aabb_max_a};
64 shammath::AABB<Tvec> aabb_b = {aabb_min_b, aabb_max_b};
65
66 bool crit = mac(aabb_a, aabb_b, theta_crit) == false;
67
68 if (crit) {
69
70 if constexpr (allow_leaf_lowering) {
71
72 bool is_a_leaf = ttrav.is_id_leaf(cell_a);
73 bool is_b_leaf = ttrav.is_id_leaf(cell_b);
74
75 if (is_a_leaf && is_b_leaf) {
76 interact_p2p.push_back({cell_a, cell_b});
77 return;
78 }
79
80 u32 child_a_1 = (is_a_leaf) ? cell_a : ttrav.get_left_child(cell_a);
81 u32 child_a_2 = (is_a_leaf) ? cell_a : ttrav.get_right_child(cell_a);
82 u32 child_b_1 = (is_b_leaf) ? cell_b : ttrav.get_left_child(cell_b);
83 u32 child_b_2 = (is_b_leaf) ? cell_b : ttrav.get_right_child(cell_b);
84
85 bool run_a_1 = true;
86 bool run_a_2 = !is_a_leaf;
87 bool run_b_1 = true;
88 bool run_b_2 = !is_b_leaf;
89
90 if (run_a_1 && run_b_1)
91 dtt_child_call(child_a_1, child_b_1);
92 if (run_a_2 && run_b_1)
93 dtt_child_call(child_a_2, child_b_1);
94 if (run_a_1 && run_b_2)
95 dtt_child_call(child_a_1, child_b_2);
96 if (run_a_2 && run_b_2)
97 dtt_child_call(child_a_2, child_b_2);
98
99 } else {
100
101 u32 child_a_1 = ttrav.get_left_child(cell_a);
102 u32 child_a_2 = ttrav.get_right_child(cell_a);
103 u32 child_b_1 = ttrav.get_left_child(cell_b);
104 u32 child_b_2 = ttrav.get_right_child(cell_b);
105
106 bool child_a_1_leaf = ttrav.is_id_leaf(child_a_1);
107 bool child_a_2_leaf = ttrav.is_id_leaf(child_a_2);
108 bool child_b_1_leaf = ttrav.is_id_leaf(child_b_1);
109 bool child_b_2_leaf = ttrav.is_id_leaf(child_b_2);
110
111 if (child_a_1_leaf || child_a_2_leaf || child_b_1_leaf || child_b_2_leaf) {
112 interact_p2p.push_back({cell_a, cell_b});
113 return;
114 }
115
116 dtt_child_call(child_a_1, child_b_1);
117 dtt_child_call(child_a_2, child_b_1);
118 dtt_child_call(child_a_1, child_b_2);
119 dtt_child_call(child_a_2, child_b_2);
120 }
121
122 } else {
123 interact_m2l.push_back({cell_a, cell_b});
124 }
125 }
126
127 inline static void dtt_recursive_ref(
129 Tscal theta_crit,
130 std::vector<u32_2> &interact_m2l,
131 std::vector<u32_2> &interact_p2p,
132 bool allow_leaf_lowering) {
133
135
136 auto obj_it_host = bvh.get_object_iterator_host();
137 auto acc = obj_it_host.get_read_access();
138
139 auto &ttrav = acc.tree_traverser.tree_traverser;
140
141 // Is the root a leaf ?
142 if (ttrav.is_id_leaf(0)) {
143 interact_p2p.push_back({0, 0});
144 return;
145 }
146
148 if (allow_leaf_lowering) {
149 dtt_recursive_internal<true>(0, 0, acc, theta_crit, interact_m2l, interact_p2p);
150 } else {
151 dtt_recursive_internal<false>(0, 0, acc, theta_crit, interact_m2l, interact_p2p);
152 }
153 }
154
155 inline static shamtree::DTTResult dtt(
156 sham::DeviceScheduler_ptr dev_sched,
158 shambase::VecComponent<Tvec> theta_crit,
159 bool ordered_result,
160 bool allow_leaf_lowering) {
161 StackEntry stack_loc{};
162
163 std::vector<u32_2> interact_m2l{};
164 std::vector<u32_2> interact_p2p{};
165
166 dtt_recursive_ref(bvh, theta_crit, interact_m2l, interact_p2p, allow_leaf_lowering);
167
168 sham::DeviceBuffer<u32_2> interact_m2l_buf(interact_m2l.size(), dev_sched);
169 sham::DeviceBuffer<u32_2> interact_p2p_buf(interact_p2p.size(), dev_sched);
170
171 interact_m2l_buf.copy_from_stdvec(interact_m2l);
172 interact_p2p_buf.copy_from_stdvec(interact_p2p);
173
174 // while we could have built the return object directly here, we instead build it
175 // afterward to avoid an issue with clang-tidy complaining when initializing under the
176 // hood multiple unique_ptr in a structured binding initialization
177 // see : https://github.com/llvm/llvm-project/issues/153300
178 DTTResult result{std::move(interact_m2l_buf), std::move(interact_p2p_buf)};
179
180 if (ordered_result) {
181 auto offset_m2l = sham::DeviceBuffer<u32>(0, dev_sched);
182 auto offset_p2p = sham::DeviceBuffer<u32>(0, dev_sched);
183
184 shamtree::details::reorder_scan_dtt_result(
185 bvh.structure.get_total_cell_count(), result.node_interactions_m2l, offset_m2l);
186
187 shamtree::details::reorder_scan_dtt_result(
188 bvh.structure.get_total_cell_count(), result.node_interactions_p2p, offset_p2p);
189
190 DTTResult::OrderedResult ordering{std::move(offset_m2l), std::move(offset_p2p)};
191
192 result.ordered_result = std::move(ordering);
193 }
194
195 return result;
196 }
197 };
198} // namespace shamtree::details
Dual tree traversal algorithm for Compressed Leaf Bounding Volume Hierarchies.
std::uint32_t u32
32 bit unsigned integer
A buffer allocated in USM (Unified Shared Memory)
A Compressed Leaf Bounding Volume Hierarchy (CLBVH) for neighborhood queries.
KarrasRadixTree structure
The tree structure.
This file contains the definition for the stacktrace related functionality.
#define __shamrock_stack_entry()
Macro to create a stack entry.
Axis-Aligned bounding box.
Definition AABB.hpp:99
host version of the object iterator
CLBVHObjectIteratorAccessed< Tmorton, Tvec, dim > acc
shorthand for CLBVHObjectIteratorAccessed
Result structure for dual tree traversal operations.
static void dtt_recursive_ref(const shamtree::CompressedLeafBVH< Tmorton, Tvec, dim > &bvh, Tscal theta_crit, std::vector< u32_2 > &interact_m2l, std::vector< u32_2 > &interact_p2p, bool allow_leaf_lowering)
static void dtt_recursive_internal(u32 cell_a, u32 cell_b, const ObjItHostAcc &acc, Tscal theta_crit, std::vector< u32_2 > &interact_m2l, std::vector< u32_2 > &interact_p2p)
We make the assumption that the root is not a leaf.