Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
ComputeGravWave.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
16
27
28namespace shammodels::common::modules {
29
30 namespace {
31
32 // 3x3 mdspan view over a fixed-size array
33 template<class Tscal>
34 using Mat3 = std::mdspan<Tscal, std::extents<std::size_t, 3, 3>>;
35
36 } // namespace
37
38 template<class Tvec>
40
42
43 auto edges = get_edges();
44
45 edges.spans_positions.check_sizes(edges.sizes.indexes);
46 edges.spans_velocities.check_sizes(edges.sizes.indexes);
47 edges.spans_accelerations.check_sizes(edges.sizes.indexes);
48 edges.spans_masses.check_sizes(edges.sizes.indexes);
49 edges.spans_accel_ext.check_sizes(edges.sizes.indexes);
50
51 const Tvec x0 = edges.central_pos.data;
52 const Tvec v0 = edges.central_vel.data;
53 const Tvec a0 = edges.central_acc.data;
54 const Tscal fac = edges.gw_prefactor.data;
55 const Tscal theta_deg = edges.theta_gw.data;
56 const Tscal phi_deg = edges.phi_gw.data;
57
58 constexpr Tscal pi = shambase::constants::pi<Tscal>;
59
60 auto dev_sched = shamsys::instance::get_compute_scheduler_ptr();
61
62 // thought you could pass a DeviceBuffer to distributed_data_kernel_call through Multiref ?
63 // guess NOT motherfcker
64 // sham::DeviceBuffer<Tscal> ddq0{npart, dev_sched};
65
66 auto make_ddq = [&]() {
67 return edges.sizes.indexes.template map<sham::DeviceBuffer<Tscal>>(
68 [&](u64 id, const u32 &n) {
69 return sham::DeviceBuffer<Tscal>{n, dev_sched};
70 });
71 };
72
79
81 dev_sched,
83 edges.spans_positions.get_spans(),
84 edges.spans_velocities.get_spans(),
85 edges.spans_accelerations.get_spans(),
86 edges.spans_masses.get_spans(),
87 edges.spans_accel_ext.get_spans()},
88 sham::DDMultiRef{ddq0, ddq1, ddq2, ddq3, ddq4, ddq5},
89 edges.sizes.indexes,
90 [x0, v0, a0](
91 u32 gid,
92 const Tvec *xyz,
93 const Tvec *vxyz,
94 const Tvec *axyz,
95 const Tscal *mass,
96 const Tvec *axyz_ext,
97 Tscal *ddq0,
98 Tscal *ddq1,
99 Tscal *ddq2,
100 Tscal *ddq3,
101 Tscal *ddq4,
102 Tscal *ddq5) {
103 const Tscal m = mass[gid];
104
105 const Tscal x = xyz[gid][0] - x0[0];
106 const Tscal y = xyz[gid][1] - x0[1];
107 const Tscal z = xyz[gid][2] - x0[2];
108 const Tscal vx = vxyz[gid][0] - v0[0];
109 const Tscal vy = vxyz[gid][1] - v0[1];
110 const Tscal vz = vxyz[gid][2] - v0[2];
111
112 // normally axyz should have axyzext added to it already
113 const Tscal ax = axyz[gid][0] - a0[0];
114 const Tscal ay = axyz[gid][1] - a0[1];
115 const Tscal az = axyz[gid][2] - a0[2];
116
117 ddq0[gid] = m * (Tscal(2.) * vx * vx + x * ax + x * ax);
118 ddq1[gid] = m * (Tscal(2.) * vx * vy + x * ay + y * ax);
119 ddq2[gid] = m * (Tscal(2.) * vx * vz + x * az + z * ax);
120 ddq3[gid] = m * (Tscal(2.) * vy * vy + y * ay + y * ay);
121 ddq4[gid] = m * (Tscal(2.) * vy * vz + y * az + z * ay);
122 ddq5[gid] = m * (Tscal(2.) * vz * vz + z * az + z * az);
123 });
124
125 // Tscal ddq0_per_rank = shamalgs::primitives::sum(dev_sched, ddq0, 0, npart);
126
127 Tscal ddq0_per_rank = 0, ddq1_per_rank = 0, ddq2_per_rank = 0, ddq3_per_rank = 0,
128 ddq4_per_rank = 0, ddq5_per_rank = 0;
129
130 edges.sizes.indexes.for_each([&](u64 id, const u32 &n) {
131 ddq0_per_rank += shamalgs::primitives::sum(dev_sched, ddq0.get(id), 0, n);
132 ddq1_per_rank += shamalgs::primitives::sum(dev_sched, ddq1.get(id), 0, n);
133 ddq2_per_rank += shamalgs::primitives::sum(dev_sched, ddq2.get(id), 0, n);
134 ddq3_per_rank += shamalgs::primitives::sum(dev_sched, ddq3.get(id), 0, n);
135 ddq4_per_rank += shamalgs::primitives::sum(dev_sched, ddq4.get(id), 0, n);
136 ddq5_per_rank += shamalgs::primitives::sum(dev_sched, ddq5.get(id), 0, n);
137 });
138
139 edges.ddq.data[0] = shamalgs::collective::allreduce_sum(ddq0_per_rank);
140 edges.ddq.data[1] = shamalgs::collective::allreduce_sum(ddq1_per_rank);
141 edges.ddq.data[2] = shamalgs::collective::allreduce_sum(ddq2_per_rank);
142 edges.ddq.data[3] = shamalgs::collective::allreduce_sum(ddq3_per_rank);
143 edges.ddq.data[4] = shamalgs::collective::allreduce_sum(ddq4_per_rank);
144 edges.ddq.data[5] = shamalgs::collective::allreduce_sum(ddq5_per_rank);
145
146 std::array<Tscal, 9> Q_arr{};
147 Mat3<Tscal> Q(Q_arr.data());
148 Q(0, 0) = edges.ddq.data[0];
149 Q(0, 1) = Q(1, 0) = edges.ddq.data[1];
150 Q(0, 2) = Q(2, 0) = edges.ddq.data[2];
151 Q(1, 1) = edges.ddq.data[3];
152 Q(1, 2) = Q(2, 1) = edges.ddq.data[4];
153 Q(2, 2) = edges.ddq.data[5];
154
155 std::array<Tscal, 9> ddq_xy_arr{};
156 Mat3<Tscal> ddq_xy(ddq_xy_arr.data());
157
158 const bool rotate = std::abs(theta_deg) > static_cast<Tscal>(1e-30);
159 if (rotate) {
160 const Tscal lam = theta_deg * pi / static_cast<Tscal>(180);
161 const Tscal c = std::cos(lam);
162 const Tscal s = std::sin(lam);
163
164 std::array<Tscal, 9> R_arr
165 = {c, Tscal(0), s, Tscal(0), Tscal(1), Tscal(0), -s, Tscal(0), c};
166 Mat3<Tscal> R(R_arr.data());
167
168 std::array<Tscal, 9> inter_arr{};
169 Mat3<Tscal> inter(inter_arr.data());
170 for (std::size_t i = 0; i < 3; ++i) {
171 for (std::size_t j = 0; j < 3; ++j) {
172 Tscal sum = Tscal(0);
173 for (std::size_t k = 0; k < 3; ++k) {
174 sum += Q(i, k) * R(k, j);
175 }
176 inter(i, j) = sum;
177 }
178 }
179
180 for (std::size_t i = 0; i < 3; ++i) {
181 for (std::size_t j = 0; j < 3; ++j) {
182 Tscal sum = Tscal(0);
183 for (std::size_t k = 0; k < 3; ++k) {
184 sum += R(k, i) * inter(k, j);
185 }
186 ddq_xy(i, j) = sum;
187 }
188 }
189 } else {
190 for (std::size_t i = 0; i < 9; ++i) {
191 ddq_xy_arr[i] = Q_arr[i];
192 }
193 }
194
195 // h+ / hx
196 const Tscal phi = phi_deg * pi / static_cast<Tscal>(180);
197 const Tscal sinphi = std::sin(phi);
198 const Tscal cosphi = std::cos(phi);
199 const Tscal sinphi2 = sinphi * sinphi;
200 const Tscal cosphi2 = cosphi * cosphi;
201 const Tscal sin2phi = std::sin(Tscal(2) * phi);
202 const Tscal cos2phi = std::cos(Tscal(2) * phi);
203
204 std::array<Tscal, 4> hx_out{};
205 std::array<Tscal, 4> hp_out{};
206
207 for (u32 i = 0; i < 4; ++i) {
208 const Tscal eta = static_cast<Tscal>(i) * pi / static_cast<Tscal>(6);
209 const Tscal sineta = std::sin(eta);
210 const Tscal coseta = std::cos(eta);
211 const Tscal sineta2 = sineta * sineta;
212 const Tscal coseta2 = coseta * coseta;
213 const Tscal sin2eta = std::sin(Tscal(2) * eta);
214
215 hp_out[i] = fac
216 * (ddq_xy(0, 0) * (cosphi2 - sinphi2 * coseta2)
217 + ddq_xy(1, 1) * (sinphi2 - cosphi2 * coseta2) - ddq_xy(2, 2) * sineta2
218 - ddq_xy(0, 1) * sin2phi * (Tscal(1) + coseta2)
219 + ddq_xy(0, 2) * sinphi * sin2eta + ddq_xy(1, 2) * cosphi * sin2eta);
220
221 hx_out[i] = Tscal(2) * fac
222 * (Tscal(0.5) * (ddq_xy(0, 0) - ddq_xy(1, 1)) * sin2phi * coseta
223 + ddq_xy(0, 1) * cos2phi * coseta - ddq_xy(0, 2) * cosphi * sineta
224 + ddq_xy(1, 2) * sinphi * sineta);
225 }
226
227 edges.ddq_xy.data = ddq_xy_arr;
228 edges.hx.data = hx_out;
229 edges.hp.data = hp_out;
230 }
231
232 template<class Tvec>
233 inline std::string ComputeGravWave<Tvec>::_impl_get_tex() const {
234 std::string tex = R"tex(
235 Gravitational-wave strain from the quadrupole formula
236 (Toscani et al. 2021)
237
238 \begin{align}
239 r_i &= {spans_positions}_i - {central_pos}_i\\
240 v_i &= {spans_velocities}_i - {central_vel}_i\\
241 a_i &= {spans_accelerations}_i - {central_acc}_i + {spans_accel_ext}_i\\
242 \ddot Q_{ij} &= \sum_p {spans_masses}_p
243 \left(2 v_i v_j + r_i a_j + r_j a_i\right)\\
244 R &= \begin{pmatrix}
245 \cos\lambda & 0 & \sin\lambda\\
246 0 & 1 & 0\\
247 -\sin\lambda & 0 & \cos\lambda
248 \end{pmatrix},\quad
249 \lambda = {theta_gw}\,\frac{\pi}{180}\\
250 \ddot Q^{xy} &= R^{T}\,\ddot Q\,R\\
251 h_+(\eta,\phi) &= {gw_prefactor}\,
252 \Big[\ddot Q^{xy}_{11}(\cos^2\phi - \sin^2\phi\cos^2\eta)
253 + \ddot Q^{xy}_{22}(\sin^2\phi - \cos^2\phi\cos^2\eta)
254 - \ddot Q^{xy}_{33}\sin^2\eta\\
255 &\qquad - \ddot Q^{xy}_{12}\sin 2\phi\,(1 + \cos^2\eta)
256 + \ddot Q^{xy}_{13}\sin\phi\,\sin 2\eta
257 + \ddot Q^{xy}_{23}\cos\phi\,\sin 2\eta\Big]\\
258 h_\times(\eta,\phi) &= 2\,{gw_prefactor}\,
259 \Big[\tfrac12(\ddot Q^{xy}_{11} - \ddot Q^{xy}_{22})\sin 2\phi\,\cos\eta\\
260 &\qquad + \ddot Q^{xy}_{12}\cos 2\phi\,\cos\eta
261 - \ddot Q^{xy}_{13}\cos\phi\,\sin\eta
262 + \ddot Q^{xy}_{23}\sin\phi\,\sin\eta\Big]
263 \end{align}
264
265 Evaluated at $\eta = 0,\ \pi/6,\ \pi/3,\ \pi/2$
266 with $\phi = {phi_gw}^\circ$, giving {hx} and {hp}.
267 )tex";
268
269 replace_edges_tex_symbols(tex);
270
271 return tex;
272 }
273
275
276} // namespace shammodels::common::modules
Compute the gravitational wave quadrupole. Based on Toscani et. al. 2021.
Header file describing a Node Instance.
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
A buffer allocated in USM (Unified Shared Memory).
Represents a collection of objects distributed across patches identified by a u64 id.
T & get(u64 id)
Returns a reference to an object in the collection.
virtual std::string _impl_get_tex() const
get the tex of the node
Class holding the value of numerous constants generated from the following source.
void distributed_data_kernel_call(sham::DeviceScheduler_ptr dev_sched, RefIn in, RefOut in_out, const shambase::DistributedData< index_t > &thread_counts, Functor &&func)
A variant of sham::kernel_call for distributed data.
T sum(const sham::DeviceScheduler_ptr &sched, const sham::DeviceBuffer< T > &buf1, u32 start_id, u32 end_id)
Compute the sum of elements in a device buffer within a specified range.
#define __shamrock_stack_entry()
Macro to create a stack entry.
A variant of sham::MultiRef for distributed data.