Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
SinkParticlesUpdate.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
17
25#include "shamcomm/logs.hpp"
40#include <shambackends/sycl.hpp>
41#include <memory>
42#include <vector>
43
44#define NODE_EDGES(X_RO, X_RW) \
45 /* ------------------- (field) inputs ------------------- */ \
46 X_RO(shamrock::solvergraph::Indexes<u32>, part_counts) \
47 X_RO(shamrock::solvergraph::IFieldSpan<Tvec>, positions) \
48 \
49 /* ------------------- (sink) inputs ------------------- */ \
50 X_RO(shamrock::solvergraph::IDataEdge<std::vector<Tvec>>, sink_positions) \
51 X_RO(shamrock::solvergraph::IDataEdge<std::vector<Tscal>>, sink_accr_radii) \
52 \
53 /* ------------------- outputs ------------------- */ \
54 /* sink_accretion_table[id_a] = who should accrete part [id_a] (or u32_max if none); */ \
55 X_RW(shamrock::solvergraph::Field<u32>, sink_accretion_table)
56
57namespace shammodels::common::modules {
58 template<class Tvec>
59 class SinkParticlesFlagAccreteHard : public shamrock::solvergraph::INode,
61
62 using Tscal = shambase::VecComponent<Tvec>;
63
64 std::unique_ptr<sham::DeviceBuffer<Tvec>> sink_pos;
65 std::unique_ptr<sham::DeviceBuffer<Tscal>> sink_accr_radii;
66
67 public:
68 SinkParticlesFlagAccreteHard() = default;
69
70 EXPAND_NODE_EDGES(NODE_EDGES)
71
73
75
76 auto edges = get_edges();
77
78 auto dev_sched = shamsys::instance::get_compute_scheduler_ptr();
79 auto &q = shambase::get_check_ref(dev_sched).get_queue();
80
81 auto &sink_positions = edges.sink_positions.data;
82 auto &sink_radii = edges.sink_accr_radii.data;
83
84 if (sink_positions.size() != sink_radii.size()) {
86 "Sink positions and accretion radii must have the same size");
87 }
88
89 if (!sink_pos) {
90 sink_pos
91 = std::make_unique<sham::DeviceBuffer<Tvec>>(sink_positions.size(), dev_sched);
92 }
93 if (!sink_accr_radii) {
94 sink_accr_radii
95 = std::make_unique<sham::DeviceBuffer<Tscal>>(sink_radii.size(), dev_sched);
96 }
97
98 sink_pos->resize(sink_positions.size());
99 sink_accr_radii->resize(sink_radii.size());
100
101 sink_pos->copy_from_stdvec(sink_positions);
102 sink_accr_radii->copy_from_stdvec(sink_radii);
103
104 edges.positions.check_sizes(edges.part_counts.indexes);
105 edges.sink_accretion_table.ensure_sizes(edges.part_counts.indexes);
106
107 auto &pos_spans = edges.positions.get_spans();
108 auto &table_acc_spans = edges.sink_accretion_table.get_spans();
109
110 u32 sink_count = shambase::narrow_or_throw<u32>(sink_positions.size());
111
112 edges.part_counts.indexes.for_each([&](u64 id_patch, u32 part_count) {
114 q,
115 sham::MultiRef{pos_spans.get(id_patch), *sink_pos, *sink_accr_radii},
116 sham::MultiRef{table_acc_spans.get(id_patch)},
117 part_count,
118 [sink_count](
119 u32 id_a,
120 const Tvec *__restrict part_pos,
121 const Tvec *__restrict sink_pos,
122 const Tscal *__restrict sink_accr_radii,
123 u32 *__restrict sink_accretion_table) {
124 Tvec r_a = part_pos[id_a];
125
126 u32 result = u32_max;
127
128 for (u32 i_sink = 0; i_sink < sink_count; i_sink++) {
129 Tscal acc_radii = sink_accr_radii[i_sink];
130 Tvec d = r_a - sink_pos[i_sink];
131
132 bool should_accrete = sycl::dot(d, d) <= acc_radii * acc_radii;
133 if (should_accrete) {
134 result = i_sink;
135 break;
136 }
137 }
138
139 sink_accretion_table[id_a] = result;
140 });
141 });
142 }
143
144 inline void free_alloc() {
145 sink_pos = {};
146 sink_accr_radii = {};
147 }
148
149 inline virtual std::string _impl_get_label() const {
150 return "SinkParticlesFlagAccreteHard";
151 }
152
153 inline virtual std::string _impl_get_tex() const { return "TODO"; }
154 };
155} // namespace shammodels::common::modules
156
157#undef NODE_EDGES
158
159#define NODE_EDGES(X_RO, X_RW) \
160 /* ------------------- (param) inputs ------------------- */ \
161 X_RO(shamrock::solvergraph::IDataEdge<Tscal>, gpart_mass) \
162 X_RO(shamrock::solvergraph::IDataEdge<Tscal>, dt) \
163 \
164 /* ------------------- (field) inputs ------------------- */ \
165 X_RO(shamrock::solvergraph::Indexes<u32>, part_counts) \
166 X_RO(shamrock::solvergraph::IFieldSpan<Tvec>, positions) \
167 X_RO(shamrock::solvergraph::IFieldSpan<Tvec>, velocities) \
168 X_RO(shamrock::solvergraph::IFieldSpan<Tvec>, accelerations) \
169 \
170 /* ------------------- (sink) accretion table ------------------- */ \
171 X_RW(shamrock::solvergraph::Field<u32>, sink_accretion_table) \
172 \
173 /* ------------------- (sink) in/out ------------------- */ \
174 X_RW(shamrock::solvergraph::IDataEdge<std::vector<Tvec>>, sink_positions) \
175 X_RW(shamrock::solvergraph::IDataEdge<std::vector<Tvec>>, sink_velocities) \
176 X_RW(shamrock::solvergraph::IDataEdge<std::vector<Tvec>>, sink_accelerations) \
177 X_RW(shamrock::solvergraph::IDataEdge<std::vector<Tvec>>, sink_angmom) \
178 X_RW(shamrock::solvergraph::IDataEdge<std::vector<Tscal>>, sink_mass)
179
180namespace shammodels::common::modules {
181 template<class Tvec>
182 class SinkParticlesAccreteQuantities : public shamrock::solvergraph::INode {
183
184 using Tscal = shambase::VecComponent<Tvec>;
185
186 public:
187 SinkParticlesAccreteQuantities() = default;
188
189 EXPAND_NODE_EDGES(NODE_EDGES)
190
192
194
195 auto edges = get_edges();
196
197 auto dev_sched = shamsys::instance::get_compute_scheduler_ptr();
198 auto &q = shambase::get_check_ref(dev_sched).get_queue();
199
200 Tscal gpart_mass = edges.gpart_mass.data;
201 Tscal dt = edges.dt.data;
202
203 sham::DeviceBuffer<u32> acc_flag(0, dev_sched);
204
205 bool had_accretion = false;
206 std::string log = "sink accretion :";
207
208 auto &sink_positions = edges.sink_positions.data;
209 auto &sink_velocities = edges.sink_velocities.data;
210 auto &sink_accelerations = edges.sink_accelerations.data;
211 auto &sink_angmom = edges.sink_angmom.data;
212 auto &sink_mass = edges.sink_mass.data;
213
214 u32 sink_count = shambase::narrow_or_throw<u32>(sink_positions.size());
215 for (u32 i_sink = 0; i_sink < sink_count; i_sink++) {
216
217 Tvec r_sink = sink_positions[i_sink];
218 Tvec v_sink = sink_velocities[i_sink];
219
220 // compute the accreted mass, position moment and linear momentum
221 Tscal s_acc_mass = 0;
222 Tvec s_acc_mxyz = {0, 0, 0};
223 Tvec s_acc_pxyz = {0, 0, 0};
224 Tvec s_acc_maxyz = {0, 0, 0};
225 Tvec s_acc_lxyz = {0, 0, 0};
226
227 edges.part_counts.indexes.for_each([&](u64 id_patch, u32 Nobj) {
228 acc_flag.resize(Nobj);
229
230 auto &acc_table = edges.sink_accretion_table.get_spans().get(id_patch);
231
233 q,
234 sham::MultiRef{acc_table},
235 sham::MultiRef{acc_flag},
236 Nobj,
237 [i_sink](
238 u32 id_a, const u32 *__restrict acc_table, u32 *__restrict acc_flag) {
239 acc_flag[id_a] = (acc_table[id_a] == i_sink) ? 1 : 0;
240 });
241
242 auto id_list_accrete = shamalgs::stream_compact(dev_sched, acc_flag, Nobj);
243
244 auto &pos_data = edges.positions.get_spans().get(id_patch);
245 auto &vel_data = edges.velocities.get_spans().get(id_patch);
246 auto &acc_data = edges.accelerations.get_spans().get(id_patch);
247
248 // sum accreted values onto sink
249 if (id_list_accrete.get_size() > 0) {
250 u32 Naccrete = shambase::narrow_or_throw<u32>(id_list_accrete.get_size());
251
252 Tscal acc_mass = gpart_mass * Naccrete;
253
254 sham::DeviceBuffer<Tvec> pxyz_acc(Naccrete, dev_sched);
255 sham::DeviceBuffer<Tvec> maxyz_acc(Naccrete, dev_sched);
256 sham::DeviceBuffer<Tvec> mxyz_acc(Naccrete, dev_sched);
257 sham::DeviceBuffer<Tvec> lxyz_acc(Naccrete, dev_sched);
258
260 q,
261 sham::MultiRef{pos_data, vel_data, acc_data, id_list_accrete},
262 sham::MultiRef{pxyz_acc, mxyz_acc, maxyz_acc, lxyz_acc},
263 Naccrete,
264 [r_sink, v_sink, gpart_mass, dt](
265 u32 id_a,
266 const Tvec *__restrict xyz,
267 const Tvec *__restrict vxyz,
268 const Tvec *__restrict axyz,
269 const u32 *__restrict id_acc,
270 Tvec *__restrict accretion_p,
271 Tvec *__restrict accretion_mr,
272 Tvec *__restrict accretion_ma,
273 Tvec *__restrict accretion_l) {
274 u32 i_a = id_acc[id_a];
275 Tvec r = xyz[i_a];
276 Tvec v = vxyz[i_a];
277 Tvec a = axyz[i_a];
278 accretion_p[id_a] = gpart_mass * v;
279 accretion_mr[id_a] = gpart_mass * r;
280 accretion_ma[id_a] = gpart_mass * a;
281
282 // dirty trick to account for the residual acceleration in the spin.
283 // This allows us to maitain a much better angular momentum
284 // conservation.
285 v += a * dt / 2;
286 accretion_l[id_a]
287 = gpart_mass * sycl::cross(r - r_sink, v - v_sink);
288 });
289
290 Tvec acc_pxyz = shamalgs::primitives::sum(dev_sched, pxyz_acc, 0, Naccrete);
291 Tvec acc_mxyz = shamalgs::primitives::sum(dev_sched, mxyz_acc, 0, Naccrete);
292 Tvec acc_maxyz
293 = shamalgs::primitives::sum(dev_sched, maxyz_acc, 0, Naccrete);
294 Tvec acc_lxyz = shamalgs::primitives::sum(dev_sched, lxyz_acc, 0, Naccrete);
295
296 s_acc_mass += acc_mass;
297 s_acc_pxyz += acc_pxyz;
298 s_acc_mxyz += acc_mxyz;
299 s_acc_maxyz += acc_maxyz;
300 s_acc_lxyz += acc_lxyz;
301 }
302 });
303
304 Tscal sum_acc_mass = shamalgs::collective::allreduce_sum(s_acc_mass);
305
306 // if there is accretion continue otherwise skip that part
307 if (sum_acc_mass <= 0) {
308 continue;
309 }
310
311 Tvec sum_acc_pxyz = shamalgs::collective::allreduce_sum(s_acc_pxyz);
312 Tvec sum_acc_mxyz = shamalgs::collective::allreduce_sum(s_acc_mxyz);
313 Tvec sum_acc_maxyz = shamalgs::collective::allreduce_sum(s_acc_maxyz);
314 Tvec sum_acc_lxyz = shamalgs::collective::allreduce_sum(s_acc_lxyz);
315
316 Tscal old_mass = sink_mass[i_sink];
317 Tvec old_pos = sink_positions[i_sink];
318 Tvec old_vel = sink_velocities[i_sink];
319 Tvec old_acc = sink_accelerations[i_sink];
320 Tvec old_ang = sink_angmom[i_sink];
321
322 // compute the new sink values
323 Tscal new_mass = old_mass + sum_acc_mass;
324 Tvec new_pos = (sum_acc_mxyz + old_pos * old_mass) / (old_mass + sum_acc_mass);
325 Tvec new_vel = (sum_acc_pxyz + old_vel * old_mass) / (old_mass + sum_acc_mass);
326 Tvec new_acc = (sum_acc_maxyz + old_acc * old_mass) / (old_mass + sum_acc_mass);
327 Tvec new_ang_mom = old_ang + sum_acc_lxyz
328 - new_mass * sycl::cross(new_pos - old_pos, new_vel - old_vel);
329
330 // write back the update sink state
331 sink_mass[i_sink] = new_mass;
332 sink_positions[i_sink] = new_pos;
333 sink_velocities[i_sink] = new_vel;
334 sink_angmom[i_sink] = new_ang_mom;
335 sink_accelerations[i_sink] = new_acc;
336
337 had_accretion = true;
338 log += shambase::format(
339 "\n id {} deltas : mass={} r={} v={} l={}",
340 i_sink,
341 new_mass - old_mass,
342 new_pos - old_pos,
343 new_vel - old_vel,
344 new_ang_mom - old_ang);
345 }
346
347 if (shamcomm::world_rank() == 0 && had_accretion) {
348 logger::info_ln("sph::Sink", log);
349 }
350 }
351
352 inline virtual std::string _impl_get_label() const {
353 return "SinkParticlesAccreteQuantities";
354 }
355
356 inline virtual std::string _impl_get_tex() const { return "TODO"; }
357 };
358} // namespace shammodels::common::modules
359
360#undef NODE_EDGES
361
362#define NODE_EDGES(X_RO, X_RW) \
363 /* ------------------- (sink) accretion table ------------------- */ \
364 X_RO(shamrock::solvergraph::Indexes<u32>, part_counts) \
365 X_RO(shamrock::solvergraph::Field<u32>, sink_accretion_table) \
366 \
367 /* ------------------- Patchdatas ------------------- */ \
368 X_RW(shamrock::solvergraph::PatchDataLayerRefs, pdats)
369
370namespace shammodels::common::modules {
371 template<class Tvec>
372 class SinkParticlesEvictAccretedParticles : public shamrock::solvergraph::INode {
373
374 using Tscal = shambase::VecComponent<Tvec>;
375
376 public:
377 SinkParticlesEvictAccretedParticles() = default;
378
379 EXPAND_NODE_EDGES(NODE_EDGES)
380
382
384
385 auto edges = get_edges();
386
387 auto dev_sched = shamsys::instance::get_compute_scheduler_ptr();
388 auto &q = shambase::get_check_ref(dev_sched).get_queue();
389
390 sham::DeviceBuffer<u32> keep_flag(0, dev_sched);
391 sham::DeviceBuffer<int> accr_flag(1, dev_sched);
392
393 edges.part_counts.indexes.for_each([&](u64 id_patch, u32 Nobj) {
394 auto &pdat = edges.pdats.get(id_patch);
395 auto &acc_table = edges.sink_accretion_table.get_spans().get(id_patch);
396
397 keep_flag.resize(Nobj);
398 accr_flag.fill(0);
399
401 q,
402 sham::MultiRef{acc_table},
403 sham::MultiRef{keep_flag, accr_flag},
404 Nobj,
405 [](u32 id_a,
406 const u32 *__restrict acc_table,
407 u32 *__restrict keep_flag,
408 int *__restrict accr_flag) {
409 bool keep = acc_table[id_a] == u32_max;
410 keep_flag[id_a] = keep ? 1 : 0;
411
412 sycl::atomic_ref<
413 int,
414 sycl::memory_order_relaxed,
415 sycl::memory_scope_device,
416 sycl::access::address_space::global_space>
417 atomic_accr(accr_flag[0]);
418
419 if (!keep) {
420 atomic_accr.fetch_or(1);
421 }
422 });
423
424 int accr_flag_val = accr_flag.get_val_at_idx(0);
425
426 if (accr_flag_val != 0) {
427
428 sham::DeviceBuffer<u32> id_list_keep
429 = shamalgs::stream_compact(dev_sched, keep_flag, Nobj);
430
431 pdat.keep_ids(
432 id_list_keep, shambase::narrow_or_throw<u32>(id_list_keep.get_size()));
433 }
434 });
435 }
436
437 inline virtual std::string _impl_get_label() const {
438 return "SinkParticlesEvictAccretedParticles";
439 }
440
441 inline virtual std::string _impl_get_tex() const { return "TODO"; }
442 };
443} // namespace shammodels::common::modules
444#undef NODE_EDGES
445
446template<class Tvec, template<class> class SPHKernel>
447void shammodels::sph::modules::SinkParticlesUpdate<Tvec, SPHKernel>::accrete_particles(Tscal dt) {
448 StackEntry stack_loc{};
449
450 auto &sync = scheduler().synchronized_data;
451 if (!has_sinks<Tvec>(sync)) {
452 return;
453 }
454
455 using namespace shamrock;
456 using namespace shamrock::patch;
457 using namespace shamrock::solvergraph;
458
459 PatchDataLayerLayout &pdl = scheduler().pdl_old();
460 const u32 ixyz = pdl.get_field_idx<Tvec>("xyz");
461 const u32 ivxyz = pdl.get_field_idx<Tvec>("vxyz");
462 const u32 iaxyz = pdl.get_field_idx<Tvec>("axyz");
463
464 auto part_counts = Indexes<u32>::make_shared("part_counts", "N");
465 auto positions = std::make_shared<FieldRefs<Tvec>>("xyz", "\\mathbf{r}");
466 auto velocities = std::make_shared<FieldRefs<Tvec>>("vxyz", "\\mathbf{v}");
467 auto accelerations = std::make_shared<FieldRefs<Tvec>>("axyz", "\\mathbf{a}");
468 auto sink_accretion_table
469 = std::make_shared<Field<u32>>(1, "sink_accretion_table", "\\mathrm{acc}");
470 auto pdats = std::make_shared<PatchDataLayerRefs>("patchdatas", "\\mathbb{U}");
471
475
476 scheduler().for_each_patchdata_nonempty([&](Patch cur_p, PatchDataLayer &pdat) {
477 u64 id = cur_p.id_patch;
478 part_counts->indexes.add_obj(id, pdat.get_obj_cnt());
479 pos_dd.add_obj(id, std::ref(pdat.get_field<Tvec>(ixyz)));
480 vel_dd.add_obj(id, std::ref(pdat.get_field<Tvec>(ivxyz)));
481 acc_dd.add_obj(id, std::ref(pdat.get_field<Tvec>(iaxyz)));
482 pdats->patchdatas.add_obj(id, std::ref(pdat));
483 });
484
485 positions->set_refs(pos_dd);
486 velocities->set_refs(vel_dd);
487 accelerations->set_refs(acc_dd);
488
489 auto gpart_mass = IDataEdge<Tscal>::make_shared("gpart_mass", "m");
490 gpart_mass->data = solver_config.gpart_mass;
491
492 auto dt_edge = IDataEdge<Tscal>::make_shared("dt", "dt");
493 dt_edge->data = dt;
494
495 auto sink_positions
496 = sync.template get_edge_ptr<IDataEdgeSerializable<std::vector<Tvec>>>("sink_pos");
497 auto sink_velocities
498 = sync.template get_edge_ptr<IDataEdgeSerializable<std::vector<Tvec>>>("sink_vel");
499 auto sink_accelerations
500 = sync.template get_edge_ptr<IDataEdgeSerializable<std::vector<Tvec>>>("sink_acc_sph");
501 auto sink_angmom = sync.template get_edge_ptr<IDataEdgeSerializable<std::vector<Tvec>>>(
502 "sink_angular_momentum");
503 auto sink_mass
504 = sync.template get_edge_ptr<IDataEdgeSerializable<std::vector<Tscal>>>("sink_mass");
505 auto sink_accr_radii = sync.template get_edge_ptr<IDataEdgeSerializable<std::vector<Tscal>>>(
506 "sink_accretion_radius");
507
509 flag_node.set_edges(
510 part_counts, positions, sink_positions, sink_accr_radii, sink_accretion_table);
511 flag_node.evaluate();
512
514 qty_node.set_edges(
515 gpart_mass,
516 dt_edge,
517 part_counts,
518 positions,
519 velocities,
520 accelerations,
521 sink_accretion_table,
522 sink_positions,
523 sink_velocities,
524 sink_accelerations,
525 sink_angmom,
526 sink_mass);
527 qty_node.evaluate();
528
530 evict_node.set_edges(part_counts, sink_accretion_table, pdats);
531 evict_node.evaluate();
532
533 flag_node.free_alloc();
534}
535
536template<class Tvec, template<class> class SPHKernel>
537void shammodels::sph::modules::SinkParticlesUpdate<Tvec, SPHKernel>::predictor_step(Tscal dt) {
538
539 StackEntry stack_loc{};
540
541 auto &sync = scheduler().synchronized_data;
542 auto &pos = get_sink_pos<Tvec>(sync);
543 if (pos.empty()) {
544 return;
545 }
546
547 auto &vel = get_sink_vel<Tvec>(sync);
548 auto &acc_sph = get_sink_acc_sph<Tvec>(sync);
549 auto &acc_ext = get_sink_acc_ext<Tvec>(sync);
550
551 compute_ext_forces();
552
553 for (size_t i = 0; i < pos.size(); i++) {
554 vel[i] += (dt / 2) * (acc_sph[i] + acc_ext[i]);
555 }
556
557 for (size_t i = 0; i < pos.size(); i++) {
558 pos[i] += dt * vel[i];
559 }
560}
561
562template<class Tvec, template<class> class SPHKernel>
563void shammodels::sph::modules::SinkParticlesUpdate<Tvec, SPHKernel>::corrector_step(Tscal dt) {
564
565 StackEntry stack_loc{};
566
567 auto &sync = scheduler().synchronized_data;
568 auto &vel = get_sink_vel<Tvec>(sync);
569 if (vel.empty()) {
570 return;
571 }
572
573 auto &acc_sph = get_sink_acc_sph<Tvec>(sync);
574 auto &acc_ext = get_sink_acc_ext<Tvec>(sync);
575
576 for (size_t i = 0; i < vel.size(); i++) {
577 vel[i] += (dt / 2) * (acc_sph[i] + acc_ext[i]);
578 }
579}
580
581template<class Tvec, template<class> class SPHKernel>
582void shammodels::sph::modules::SinkParticlesUpdate<Tvec, SPHKernel>::compute_sph_forces() {
583
584 StackEntry stack_loc{};
585
586 Tscal gpart_mass = solver_config.gpart_mass;
587
588 auto &sync = scheduler().synchronized_data;
589 auto &pos = get_sink_pos<Tvec>(sync);
590 if (pos.empty()) {
591 return;
592 }
593
594 auto &mass = get_sink_mass<Tvec>(sync);
595 auto &accretion_radius = get_sink_accretion_radius<Tvec>(sync);
596 auto &acc_sph = get_sink_acc_sph<Tvec>(sync);
597
598 Tscal G = solver_config.get_constant_G();
599 Tscal epsilon_grav = 1e-9;
600
601 using namespace shamrock;
602 using namespace shamrock::patch;
603
604 PatchDataLayerLayout &pdl = scheduler().pdl_old();
605 const u32 ixyz = pdl.get_field_idx<Tvec>("xyz");
606 const u32 iaxyz_ext = pdl.get_field_idx<Tvec>("axyz_ext");
607
608 auto dev_sched = shamsys::instance::get_compute_scheduler_ptr();
609 sham::DeviceQueue &q = shambase::get_check_ref(dev_sched).get_queue();
610
611 std::vector<Tvec> result_acc_sinks{};
612
613 for (size_t sink_id = 0; sink_id < pos.size(); sink_id++) {
614
615 Tvec sph_acc_sink = {};
616
617 scheduler().for_each_patchdata_nonempty(
618 [&, G, epsilon_grav, gpart_mass](Patch cur_p, PatchDataLayer &pdat) {
619 sham::DeviceBuffer<Tvec> &buf_xyz = pdat.get_field_buf_ref<Tvec>(ixyz);
620 sham::DeviceBuffer<Tvec> &buf_axyz_ext = pdat.get_field_buf_ref<Tvec>(iaxyz_ext);
621
622 sham::DeviceBuffer<Tvec> buf_sync_axyz(pdat.get_obj_cnt(), dev_sched);
623
624 Tscal sink_mass = mass[sink_id];
625 Tscal sink_racc = accretion_radius[sink_id];
626 Tvec sink_pos = pos[sink_id];
627
628 sham::EventList depends_list;
629 auto xyz = buf_xyz.get_read_access(depends_list);
630 auto axyz_ext = buf_axyz_ext.get_write_access(depends_list);
631 auto axyz_sync = buf_sync_axyz.get_write_access(depends_list);
632
633 auto e = q.submit(
634 depends_list,
635 [&, G, epsilon_grav, sink_mass, sink_pos, sink_racc](sycl::handler &cgh) {
636 shambase::parallel_for(
637 cgh, pdat.get_obj_cnt(), "sink-sph forces", [=](i32 id_a) {
638 Tvec r_a = xyz[id_a];
639
640 Tvec delta = r_a - sink_pos;
641 Tscal d = sycl::length(delta);
642
643 Tvec force = G * delta / (d * d * d);
644
645 // This is a hack to avoid the sink kaboom effect
646 // when the particle is being advected close to the sink before
647 // being accreted
648 if (d < sink_racc) {
649 force = {0, 0, 0};
650 }
651
652 axyz_sync[id_a] = force * gpart_mass;
653 axyz_ext[id_a] += -force * sink_mass;
654 });
655 });
656
657 buf_xyz.complete_event_state(e);
658 buf_axyz_ext.complete_event_state(e);
659 buf_sync_axyz.complete_event_state(e);
660
661 sph_acc_sink
662 += shamalgs::primitives::sum(dev_sched, buf_sync_axyz, 0, pdat.get_obj_cnt());
663 });
664
665 result_acc_sinks.push_back(sph_acc_sink);
666 }
667
668 std::vector<Tvec> gathered_result_acc_sinks{};
670 result_acc_sinks, gathered_result_acc_sinks, MPI_COMM_WORLD);
671
672 for (size_t id_s = 0; id_s < pos.size(); id_s++) {
673
674 acc_sph[id_s] = {};
675
676 for (u32 rid = 0; rid < shamcomm::world_size(); rid++) {
677 acc_sph[id_s] += gathered_result_acc_sinks[rid * pos.size() + id_s];
678 }
679 }
680}
681
682template<class Tvec, template<class> class SPHKernel>
683void shammodels::sph::modules::SinkParticlesUpdate<Tvec, SPHKernel>::compute_ext_forces() {
684
685 StackEntry stack_loc{};
686
687 auto &sync = scheduler().synchronized_data;
688 auto &pos = get_sink_pos<Tvec>(sync);
689 if (pos.empty()) {
690 return;
691 }
692
693 auto &mass = get_sink_mass<Tvec>(sync);
694 auto &acc_ext = get_sink_acc_ext<Tvec>(sync);
695
696 for (size_t i = 0; i < pos.size(); i++) {
697 acc_ext[i] = Tvec{};
698 }
699
700 Tscal G = solver_config.get_constant_G();
701 Tscal epsilon_grav_sink = 1e-9;
702
703 for (size_t i = 0; i < pos.size(); i++) {
704 Tvec sum{};
705 for (size_t j = 0; j < pos.size(); j++) {
706 Tvec rij = pos[i] - pos[j];
707 Tscal rij_scal = sycl::length(rij);
708 sum -= G * mass[j] * rij / (rij_scal * rij_scal * rij_scal + epsilon_grav_sink);
709 }
710 acc_ext[i] = sum;
711 }
712}
713
714using namespace shammath;
718
constexpr const char * xyz
Position field (3D coordinates).
constexpr const char * part_counts
Particle counts per patch.
shambase::DistributedData< PatchDataFieldRef< T > > DDPatchDataFieldRef
Alias for a DistributedData of PatchDataFieldRefs.
Header file describing a Node Instance.
Defines the PatchDataLayerRefs class for managing distributed references to patch data layers.
std::uint32_t u32
32 bit unsigned integer
std::uint64_t u64
64 bit unsigned integer
std::int32_t i32
32 bit integer
A buffer allocated in USM (Unified Shared Memory).
void complete_event_state(sycl::event e) const
Complete the event state of the buffer.
void resize(size_t new_size, bool keep_data=true)
Resizes the buffer to a given size.
void fill(T value, std::array< size_t, 2 > idx_range)
Fill a subpart of the buffer with a given value.
T get_val_at_idx(size_t idx) const
Get the value at a given index in the buffer.
size_t get_size() const
Gets the number of elements in the buffer.
const T * get_read_access(sham::EventList &depends_list, SourceLocation src_loc=SourceLocation{}) const
Get a read-only pointer to the buffer's data.
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:31
iterator add_obj(u64 id, T &&obj)
Adds a new object to the collection.
virtual std::string _impl_get_label() const
get the label of the node
virtual std::string _impl_get_tex() const
get the tex of the node
virtual std::string _impl_get_label() const
get the label of the node
virtual std::string _impl_get_tex() const
get the tex of the node
virtual std::string _impl_get_tex() const
get the tex of the node
virtual std::string _impl_get_label() const
get the label of the node
u32 get_field_idx(const std::string &field_name) const
Get the field id if matching name & type.
PatchDataLayer container class, the layout is described in patchdata_layout.
Interface for data edges that can free their allocated memory.
Definition IFreeable.hpp:28
Inode is node between data edges, takes multiple inputs, multiple outputs.
Definition INode.hpp:31
void evaluate()
Evaluate the node.
Definition INode.hpp:146
std::vector< int > vector_allgatherv(const std::vector< T > &send_vec, const MPI_Datatype &send_type, std::vector< T > &recv_vec, const MPI_Datatype &recv_type, const MPI_Comm comm)
allgatherv on vector with size query (size querying variant of vector_allgatherv_ks) //TODO add fault...
Definition exchanges.hpp:98
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.
std::tuple< std::optional< sycl::buffer< u32 > >, u32 > stream_compact(sycl::queue &q, sycl::buffer< u32 > &buf_flags, u32 len)
Stream compaction algorithm.
Definition numeric.cpp:84
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.
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:110
ExcptTypes make_except_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Create an exception with a message and a location.
i32 world_rank()
Gives the rank of the current process in the MPI communicator.
Definition worldInfo.cpp:40
i32 world_size()
Gives the size of the MPI communicator.
Definition worldInfo.cpp:38
namespace for math utility
Definition AABB.hpp:26
namespace for the main framework
Definition __init__.py:1
Utilities for safe type narrowing conversions.
constexpr u32 u32_max
u32 max value
void info_ln(std::string module_name, Types... var2)
Prints a log message with multiple arguments followed by a newline.
Definition logs.hpp:133
Helpers to access SPH sink particles stored as SoA synchronized data edges.
sph kernels
#define __shamrock_stack_entry()
Macro to create a stack entry.
shambase::details::BasicStackEntry StackEntry
Alias for shambase::details::BasicStackEntry.
A class that references multiple buffers or similar objects.
Definition MultiRef.hpp:33
Patch object that contain generic patch information.
Definition Patch.hpp:33
u64 id_patch
unique key that identify the patch
Definition Patch.hpp:86
Functions related to the MPI communicator.