Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
NodeUpdateDerivsMonofluidTVI.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
17#include "shambase/string.hpp"
22#include "shamrock/patch/PatchDataField.hpp" // IWYU pragma: keep
23
24template<class Tvec, template<class> class SPHKernel>
26 using Tscal = shambase::VecComponent<Tvec>;
27 using Kernel = SPHKernel<Tscal>;
28 static constexpr Tscal hfactd = Kernel::hfactd;
29 static constexpr Tscal Rkern = Kernel::Rkern;
30 static constexpr Tscal Rker2 = Rkern * Rkern;
31
32 Tscal pmass;
33 u32 ndust;
34
35 inline void operator()(
36 u32 thread_id,
37 // input
38 const Tvec *__restrict xyz,
39 const Tscal *__restrict hpart,
40 const Tvec *__restrict vxyz,
41 const Tscal *__restrict omega,
42 const Tscal *__restrict pressure,
43 const Tscal *__restrict s_j,
44 const Tscal *__restrict Ttilde_sj,
46 // output
47 Tscal *__restrict ds_j_dt) const {
48
49 u32 id_a = thread_id / ndust;
50 u32 jdust = thread_id % ndust;
51
52 Tscal h_a = hpart[id_a];
53 Tvec xyz_a = xyz[id_a];
54 Tvec vxyz_a = vxyz[id_a];
55 Tscal P_a = pressure[id_a];
56 Tscal omega_a = omega[id_a];
57 Tscal s_j_a = s_j[thread_id];
58 Tscal Ttilde_sj_a = Ttilde_sj[thread_id];
59
60 using namespace shamrock::sph;
61 Tscal rho_a = rho_h(pmass, h_a, Kernel::hfactd);
62 Tscal rho_a_sq = rho_a * rho_a;
63 Tscal rho_a_inv = 1. / rho_a;
64 Tscal omega_a_rho_a_inv = 1 / (omega_a * rho_a);
65
66 Tscal term1 = 0;
67 Tscal term2 = 0;
68
69 shamrock::tree::ObjectCacheIterator particle_looper(ploop_ptrs);
70 particle_looper.for_each_object(id_a, [&](u32 id_b) {
71 Tvec dr = xyz_a - xyz[id_b];
72 Tscal rab2 = sycl::dot(dr, dr);
73 Tscal h_b = hpart[id_b];
74
75 if (rab2 > h_a * h_a * Rker2 && rab2 > h_b * h_b * Rker2) {
76 return;
77 }
78
79 Tvec vxyz_b = vxyz[id_b];
80 Tscal P_b = pressure[id_b];
81 Tscal omega_b = omega[id_b];
82 Tscal s_j_b = s_j[id_b * ndust + jdust];
83 Tscal Ttilde_sj_b = Ttilde_sj[id_b * ndust + jdust];
84
85 Tscal rab = sycl::sqrt(rab2);
86 Tscal rab_inv_sat = sham::inv_sat_positive(rab);
87
88 Tscal rho_b = rho_h(pmass, h_b, Kernel::hfactd);
89
90 Tscal Fab_a = Kernel::dW_3d(rab, h_a);
91 Tscal Fab_b = Kernel::dW_3d(rab, h_b);
92
93 Tvec v_ab = vxyz_a - vxyz_b;
94
95 Tvec r_ab_unit = dr * rab_inv_sat;
96
97 Tscal F_ab_bar = (Fab_a + Fab_b) / 2;
98 Tscal delta_P = P_a - P_b;
99 Tscal Ts_weighted = (Ttilde_sj_a / rho_a + Ttilde_sj_b / rho_b);
100
101 term1 += (pmass * s_j_b / rho_b) * Ts_weighted * delta_P * F_ab_bar * rab_inv_sat;
102 term2 += pmass * sham::dot(v_ab, r_ab_unit * Fab_a);
103 });
104
105 // eq 51, Hutchison 2018
106 Tscal ds_j_dt_a = Tscal{-0.5} * term1 + (s_j_a / (2 * rho_a * omega_a)) * term2;
107
108 // if we dip in the negative range do not dip further
109 ds_j_dt_a *= (s_j_a < 0 && ds_j_dt_a < 0) ? 0 : 1;
110
111 // restore it slowly to 0
112 ds_j_dt_a += (s_j_a < 0) ? -s_j_a / (10 * Ttilde_sj_a) : 0;
113
114 ds_j_dt[thread_id] = ds_j_dt_a;
115 }
116};
117
118template<class Tvec, template<class> class SPHKernel>
121
123
124 auto edges = get_edges();
125
126 auto &part_counts_with_ghost = edges.part_counts_with_ghost.indexes;
127 auto &part_counts = edges.part_counts.indexes;
128
129 // check that all input edges have the particles with ghosts zones
130 edges.xyz.check_sizes(part_counts_with_ghost);
131 edges.hpart.check_sizes(part_counts_with_ghost);
132 edges.vxyz.check_sizes(part_counts_with_ghost);
133 edges.omega.check_sizes(part_counts_with_ghost);
134 edges.pressure.check_sizes(part_counts_with_ghost);
135 edges.s_j.check_sizes(part_counts_with_ghost);
136 edges.Ttilde_sj.check_sizes(part_counts_with_ghost);
137
138 // ensure that the output edges are of size part_counts (output without ghosts zones)
139 edges.ds_j_dt.ensure_sizes(part_counts);
140
141 const Tscal pmass = edges.gpart_mass.value;
142
144
145 auto total_specie_count = part_counts.template map<u32>([&](u64 id, u32 count) {
146 return count * ndust;
147 });
148
149 // call the kernel for each patches with part_counts.get(id_patch) threads of patch id_patch
151 shamsys::instance::get_compute_scheduler_ptr(),
153 edges.xyz.get_spans(),
154 edges.hpart.get_spans(),
155 edges.vxyz.get_spans(),
156 edges.omega.get_spans(),
157 edges.pressure.get_spans(),
158 edges.s_j.get_spans(),
159 edges.Ttilde_sj.get_spans(),
160 edges.neigh_cache},
161 sham::DDMultiRef{edges.ds_j_dt.get_spans()},
162 total_specie_count,
163 ComputeKernel{pmass, ndust});
164}
165
166template<class Tvec, template<class> class SPHKernel>
168 const {
169 auto gpart_mass = get_ro_edge_base(0).get_tex_symbol();
170 auto part_counts = get_ro_edge_base(1).get_tex_symbol();
171 auto xyz = get_ro_edge_base(3).get_tex_symbol();
172 auto hpart = get_ro_edge_base(4).get_tex_symbol();
173 auto vxyz = get_ro_edge_base(5).get_tex_symbol();
174 auto omega = get_ro_edge_base(6).get_tex_symbol();
175 auto pressure = get_ro_edge_base(7).get_tex_symbol();
176 auto s_j = get_ro_edge_base(8).get_tex_symbol();
177 auto Ttilde_sj = get_ro_edge_base(9).get_tex_symbol();
178 auto ds_j_dt = get_rw_edge_base(0).get_tex_symbol();
179
180 const std::string ndust_str = std::to_string(ndust);
181 const std::string kernel_radius_str = std::to_string(kernel_radius);
182
183 std::string tex = R"tex(
184 NodeUpdateDerivsMonofluidTVI (eq. 51, Hutchison 2018)
185
186 For gas particle $a$ and dust bin $j$:
187
188 \begin{align}
189 \rho_a &= \rho_h({gpart_mass}, {hpart}_a) \\
190 \rho_b &= \rho_h({gpart_mass}, {hpart}_b) \\
191 \mathbf{v}_{a,b} &= {vxyz}_a - {vxyz}_b \\
192 \hat{\mathbf{r}}_{a,b} &= \frac{{xyz}_a - {xyz}_b}{\lvert {xyz}_a - {xyz}_b\rvert} \\
193 F_{a,b}^a &= \mathrm{d}W_{3d}(\lvert \mathbf{r}_{a,b}\rvert, {hpart}_a) \\
194 F_{a,b}^b &= \mathrm{d}W_{3d}(\lvert \mathbf{r}_{a,b}\rvert, {hpart}_b) \\
195 \bar{F}_{a,b} &= \frac{F_{a,b}^a + F_{a,b}^b}{2} \\
196 T^{\rm w}_{j,a,b} &= \frac{{Ttilde_sj}_{j,a}}{\rho_a} + \frac{{Ttilde_sj}_{j,b}}{\rho_b}
197 \\
198 {ds_j_dt}_{j,a} &=
199 -\frac{1}{2}\sum_{b \in \mathcal{N}(a)}
200 {gpart_mass}\;
201 \frac{{s_j}_{j,b}}{\rho_b}\;
202 T^{\rm w}_{j,a,b}\;
203 ({pressure}_a - {pressure}_b)\;
204 \bar{F}_{a,b}
205 \\
206 &\quad +
207 \frac{{s_j}_{j,a}}{2\rho_a\,{omega}_a}
208 \sum_{b \in \mathcal{N}(a)}
209 {gpart_mass}\;
210 \mathbf{v}_{a,b}\cdot\left(\hat{\mathbf{r}}_{a,b} F_{a,b}^a\right)
211 \end{align}
212
213 with the neighbor set $\mathcal{N}(a)$ defined by the kernel support:
214 $\lvert \mathbf{r}_{a,b}\rvert \le \max({hpart}_a,{hpart}_b)\,{Rkern}$.
215
216 $a \in [0,{part_counts})$, $j \in [0,{ndust})$.
217 )tex";
218
219 shambase::replace_all(tex, "{gpart_mass}", gpart_mass);
220 shambase::replace_all(tex, "{part_counts}", part_counts);
221 shambase::replace_all(tex, "{xyz}", xyz);
222 shambase::replace_all(tex, "{hpart}", hpart);
223 shambase::replace_all(tex, "{vxyz}", vxyz);
224 shambase::replace_all(tex, "{omega}", omega);
225 shambase::replace_all(tex, "{pressure}", pressure);
226 shambase::replace_all(tex, "{s_j}", s_j);
227 shambase::replace_all(tex, "{Ttilde_sj}", Ttilde_sj);
228 shambase::replace_all(tex, "{ds_j_dt}", ds_j_dt);
229 shambase::replace_all(tex, "{ndust}", ndust_str);
230 shambase::replace_all(tex, "{Rkern}", kernel_radius_str);
231
232 return tex;
233}
234
235using namespace shammath;
239
std::uint32_t u32
32 bit unsigned integer
std::uint64_t u64
64 bit unsigned integer
virtual std::string _impl_get_tex() const
get the tex of the node
IEdge & get_rw_edge_base(int slot)
Get a reference to a read write edge and cast it to the type IEdge.
Definition INode.hpp:100
const IEdge & get_ro_edge_base(int slot)
Get a reference to a read only edge.
Definition INode.hpp:91
T inv_sat_positive(T v, T minvsat=T{1e-9}, T satval=T{0.}) noexcept
inverse saturated (positive numbers only)
Definition math.hpp:841
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.
void replace_all(std::string &inout, std::string_view what, std::string_view with)
replace all occurence of a search string with another
Definition string.hpp:110
namespace for math utility
Definition AABB.hpp:26
sph kernels
#define __shamrock_stack_entry()
Macro to create a stack entry.
A variant of sham::MultiRef for distributed data.