Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
SGFMMPlummer.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
19#include "shamcomm/logs.hpp"
20#include "shammath/AABB.hpp"
29
31
32 template<class Tvec, u32 mm_order>
35
36 using Umorton = u32;
38
39 auto edges = get_edges();
40
41 edges.field_axyz_ext.ensure_sizes(edges.sizes.indexes);
42
43 if (edges.sizes.indexes.get_ids().size() != 1) {
45 "Self gravity FMM mode only supports one patch so far, current number "
46 "of patches is : "
47 + std::to_string(edges.sizes.indexes.get_ids().size()));
48 }
49
50 Tscal G = edges.constant_G.data;
51 Tscal gpart_mass = edges.gpart_mass.data;
52
53 Tscal gravitational_softening = epsilon * epsilon;
54
55 using MassMoments = shammath::SymTensorCollection<Tscal, 0, mm_order - 1>;
56 static constexpr u32 mass_moment_terms = MassMoments::num_component;
57
58 auto dev_sched = shamsys::instance::get_compute_scheduler_ptr();
59 sham::DeviceQueue &q = shamsys::instance::get_compute_scheduler().get_queue();
60
61 edges.sizes.indexes
62 .for_each(
63 [&](u64 id, const u64 &n) {
64 PatchDataField<Tvec> &xyz = edges.field_xyz.get_field(id);
65 PatchDataField<Tvec> &axyz_ext = edges.field_axyz_ext.get_field(id);
66
67 Tvec bmax = xyz.compute_max();
68 Tvec bmin = xyz.compute_min();
69 shammath::AABB<Tvec> aabb(bmin, bmax);
70
71 // build the tree
72 auto bvh = RTree::make_empty(dev_sched);
73 bvh.rebuild_from_positions(
74 xyz.get_buf(), xyz.get_obj_cnt(), aabb, reduction_level);
75
76 // compute moments in leaves
77 auto mass_moments_tree = compute_tree_mass_moments<Tvec, Umorton, mm_order - 1>(
78 bvh, xyz.get_buf(), gpart_mass);
79
80 // compute the FMM force in leaves on particles
81 auto obj_it = bvh.get_object_iterator();
83 q,
84 sham::MultiRef{xyz.get_buf(), obj_it, mass_moments_tree.buf_field},
85 sham::MultiRef{axyz_ext.get_buf()},
86 bvh.structure.get_leaf_count(),
87 [theta_crit = theta_crit, gravitational_softening, gpart_mass, G](
88 u32 ileaf,
89 const Tvec *xyz,
90 auto particle_looper,
91 const Tscal *mass_moments_scal,
92 Tvec *axyz_ext) {
93 auto &tree_traverser = particle_looper.tree_traverser;
94 auto &cell_iterator = particle_looper.cell_iterator;
95
96 u32 leaf_id_tree = ileaf + tree_traverser.tree_traverser.offset_leaf;
98 tree_traverser.aabb_min[leaf_id_tree],
99 tree_traverser.aabb_max[leaf_id_tree]};
100
101 Tvec s_A = box_A_AABB.get_center();
102 Tvec delta_A = box_A_AABB.delt();
103 Tscal sz_A = sham::max_component(delta_A) / 2;
104
106
107 tree_traverser
108 .traverse_tree_base(
109 [&](u32 node_id) -> bool {
110 // mac
111
113 tree_traverser.aabb_min[node_id],
114 tree_traverser.aabb_max[node_id]};
115
116 Tvec s_B = node_aabb.get_center();
117 Tvec delta_B = node_aabb.delt();
118 Tscal sz_B = sham::max_component(delta_B) / 2;
119
120 Tvec r = s_B - s_A;
121 Tscal r_sq = r.x() * r.x() + r.y() * r.y() + r.z() * r.z();
122
123 Tscal theta = (r_sq == 0)
124 ? theta_crit * 2
125 : (sz_B + sz_A) * sycl::rsqrt(r_sq);
126
127 return theta > theta_crit;
128 },
129 [&](u32 node_id) { // p2p case
130 u32 leaf_id
131 = node_id - tree_traverser.tree_traverser.offset_leaf;
132
133 cell_iterator.for_each_in_leaf_cell(leaf_id, [&](u32 j) {
134 cell_iterator.for_each_in_leaf_cell(ileaf, [&](u32 i) {
135 Tvec R = xyz[j] - xyz[i];
136 const Tscal r_inv = sycl::rsqrt(
137 R.x() * R.x() + R.y() * R.y() + R.z() * R.z()
138 + gravitational_softening);
139 axyz_ext[i]
140 += G * gpart_mass * r_inv * r_inv * r_inv * R;
141 });
142 });
143
144 },
145 [&](u32 node_id) {
146 // multipole case
147 Tvec s_B = shammath::AABB<Tvec>{tree_traverser.aabb_min[node_id], tree_traverser.aabb_max[node_id]}.get_center();
148
149 Tvec r_fmm = s_B - s_A;
150
151 MassMoments Q_n_B = MassMoments::load(
152 mass_moments_scal
153 + node_id * MassMoments::num_component,
154 0);
155
156 auto D_n
158 get_der_tensors(r_fmm);
159
160 dM_k += shamphys::get_dM_mat(D_n, Q_n_B);
161 });
162
163 // at the end apply the grav moments on the particles
164 cell_iterator.for_each_in_leaf_cell(ileaf, [&](u32 i) {
165 Tvec a_i = xyz[i] - s_A;
166
168 from_vec(a_i);
169
170 axyz_ext[i]
171 += -G
172 * shamphys::contract_grav_moment_to_force<Tscal, mm_order>(
173 a_k, dM_k);
174 });
175 });
176 });
177 }
178} // namespace shammodels::sph::modules
179
std::uint32_t u32
32 bit unsigned integer
std::uint64_t u64
64 bit unsigned integer
A SYCL queue associated with a device and a context.
DeviceQueue & get_queue(u32 id=0)
Get a reference to a DeviceQueue.
void _impl_evaluate_internal() override
evaluate the node
Utility to get the derivatives of the Green function for gravity in Cartesian coordinates.
A Compressed Leaf Bounding Volume Hierarchy (CLBVH) for neighborhood queries.
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.
namespace for the sph model modules
#define __shamrock_stack_entry()
Macro to create a stack entry.
A class that references multiple buffers or similar objects.
Axis-Aligned bounding box.
Definition AABB.hpp:99
T delt() const
Returns the delta of the AABB.
Definition AABB.hpp:152
T get_center() const noexcept
Returns the center of the AABB.
Definition AABB.hpp:174