44#define NODE_EDGES(X_RO, X_RW) \
46 X_RO(shamrock::solvergraph::Indexes<u32>, part_counts) \
47 X_RO(shamrock::solvergraph::IFieldSpan<Tvec>, positions) \
50 X_RO(shamrock::solvergraph::IDataEdge<std::vector<Tvec>>, sink_positions) \
51 X_RO(shamrock::solvergraph::IDataEdge<std::vector<Tscal>>, sink_accr_radii) \
55 X_RW(shamrock::solvergraph::Field<u32>, sink_accretion_table)
57namespace shammodels::common::modules {
62 using Tscal = shambase::VecComponent<Tvec>;
64 std::unique_ptr<sham::DeviceBuffer<Tvec>> sink_pos;
65 std::unique_ptr<sham::DeviceBuffer<Tscal>> sink_accr_radii;
68 SinkParticlesFlagAccreteHard() =
default;
70 EXPAND_NODE_EDGES(NODE_EDGES)
76 auto edges = get_edges();
78 auto dev_sched = shamsys::instance::get_compute_scheduler_ptr();
81 auto &sink_positions = edges.sink_positions.data;
82 auto &sink_radii = edges.sink_accr_radii.data;
84 if (sink_positions.size() != sink_radii.size()) {
86 "Sink positions and accretion radii must have the same size");
91 = std::make_unique<sham::DeviceBuffer<Tvec>>(sink_positions.size(), dev_sched);
93 if (!sink_accr_radii) {
95 = std::make_unique<sham::DeviceBuffer<Tscal>>(sink_radii.size(), dev_sched);
98 sink_pos->resize(sink_positions.size());
99 sink_accr_radii->resize(sink_radii.size());
101 sink_pos->copy_from_stdvec(sink_positions);
102 sink_accr_radii->copy_from_stdvec(sink_radii);
104 edges.positions.check_sizes(edges.part_counts.indexes);
105 edges.sink_accretion_table.ensure_sizes(edges.part_counts.indexes);
107 auto &pos_spans = edges.positions.get_spans();
108 auto &table_acc_spans = edges.sink_accretion_table.get_spans();
110 u32 sink_count = shambase::narrow_or_throw<u32>(sink_positions.size());
112 edges.part_counts.indexes.for_each([&](
u64 id_patch,
u32 part_count) {
115 sham::MultiRef{pos_spans.get(id_patch), *sink_pos, *sink_accr_radii},
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];
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];
132 bool should_accrete = sycl::dot(d, d) <= acc_radii * acc_radii;
133 if (should_accrete) {
139 sink_accretion_table[id_a] = result;
146 sink_accr_radii = {};
150 return "SinkParticlesFlagAccreteHard";
159#define NODE_EDGES(X_RO, X_RW) \
161 X_RO(shamrock::solvergraph::IDataEdge<Tscal>, gpart_mass) \
162 X_RO(shamrock::solvergraph::IDataEdge<Tscal>, dt) \
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) \
171 X_RW(shamrock::solvergraph::Field<u32>, sink_accretion_table) \
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)
180namespace shammodels::common::modules {
184 using Tscal = shambase::VecComponent<Tvec>;
187 SinkParticlesAccreteQuantities() =
default;
189 EXPAND_NODE_EDGES(NODE_EDGES)
195 auto edges = get_edges();
197 auto dev_sched = shamsys::instance::get_compute_scheduler_ptr();
200 Tscal gpart_mass = edges.gpart_mass.data;
201 Tscal dt = edges.dt.data;
205 bool had_accretion =
false;
206 std::string log =
"sink accretion :";
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;
214 u32 sink_count = shambase::narrow_or_throw<u32>(sink_positions.size());
215 for (
u32 i_sink = 0; i_sink < sink_count; i_sink++) {
217 Tvec r_sink = sink_positions[i_sink];
218 Tvec v_sink = sink_velocities[i_sink];
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};
227 edges.part_counts.indexes.for_each([&](
u64 id_patch,
u32 Nobj) {
230 auto &acc_table = edges.sink_accretion_table.get_spans().get(id_patch);
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;
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);
249 if (id_list_accrete.get_size() > 0) {
250 u32 Naccrete = shambase::narrow_or_throw<u32>(id_list_accrete.get_size());
252 Tscal acc_mass = gpart_mass * Naccrete;
264 [r_sink, v_sink, gpart_mass, dt](
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];
278 accretion_p[id_a] = gpart_mass * v;
279 accretion_mr[id_a] = gpart_mass * r;
280 accretion_ma[id_a] = gpart_mass * a;
287 = gpart_mass * sycl::cross(r - r_sink, v - v_sink);
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;
304 Tscal sum_acc_mass = shamalgs::collective::allreduce_sum(s_acc_mass);
307 if (sum_acc_mass <= 0) {
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);
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];
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);
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;
337 had_accretion =
true;
338 log += shambase::format(
339 "\n id {} deltas : mass={} r={} v={} l={}",
344 new_ang_mom - old_ang);
353 return "SinkParticlesAccreteQuantities";
362#define NODE_EDGES(X_RO, X_RW) \
364 X_RO(shamrock::solvergraph::Indexes<u32>, part_counts) \
365 X_RO(shamrock::solvergraph::Field<u32>, sink_accretion_table) \
368 X_RW(shamrock::solvergraph::PatchDataLayerRefs, pdats)
370namespace shammodels::common::modules {
374 using Tscal = shambase::VecComponent<Tvec>;
377 SinkParticlesEvictAccretedParticles() =
default;
379 EXPAND_NODE_EDGES(NODE_EDGES)
385 auto edges = get_edges();
387 auto dev_sched = shamsys::instance::get_compute_scheduler_ptr();
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);
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;
414 sycl::memory_order_relaxed,
415 sycl::memory_scope_device,
416 sycl::access::address_space::global_space>
417 atomic_accr(accr_flag[0]);
420 atomic_accr.fetch_or(1);
426 if (accr_flag_val != 0) {
432 id_list_keep, shambase::narrow_or_throw<u32>(id_list_keep.
get_size()));
438 return "SinkParticlesEvictAccretedParticles";
446template<
class Tvec,
template<
class>
class SPHKernel>
447void shammodels::sph::modules::SinkParticlesUpdate<Tvec, SPHKernel>::accrete_particles(Tscal dt) {
450 auto &sync = scheduler().synchronized_data;
451 if (!has_sinks<Tvec>(sync)) {
456 using namespace shamrock::patch;
457 using namespace shamrock::solvergraph;
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}");
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));
485 positions->set_refs(pos_dd);
486 velocities->set_refs(vel_dd);
487 accelerations->set_refs(acc_dd);
489 auto gpart_mass = IDataEdge<Tscal>::make_shared(
"gpart_mass",
"m");
490 gpart_mass->data = solver_config.gpart_mass;
492 auto dt_edge = IDataEdge<Tscal>::make_shared(
"dt",
"dt");
496 = sync.template get_edge_ptr<IDataEdgeSerializable<std::vector<Tvec>>>(
"sink_pos");
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");
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");
510 part_counts, positions, sink_positions, sink_accr_radii, sink_accretion_table);
521 sink_accretion_table,
530 evict_node.set_edges(part_counts, sink_accretion_table, pdats);
533 flag_node.free_alloc();
536template<
class Tvec,
template<
class>
class SPHKernel>
537void shammodels::sph::modules::SinkParticlesUpdate<Tvec, SPHKernel>::predictor_step(Tscal dt) {
541 auto &sync = scheduler().synchronized_data;
542 auto &pos = get_sink_pos<Tvec>(sync);
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);
551 compute_ext_forces();
553 for (
size_t i = 0; i < pos.size(); i++) {
554 vel[i] += (dt / 2) * (acc_sph[i] + acc_ext[i]);
557 for (
size_t i = 0; i < pos.size(); i++) {
558 pos[i] += dt * vel[i];
562template<
class Tvec,
template<
class>
class SPHKernel>
563void shammodels::sph::modules::SinkParticlesUpdate<Tvec, SPHKernel>::corrector_step(Tscal dt) {
567 auto &sync = scheduler().synchronized_data;
568 auto &vel = get_sink_vel<Tvec>(sync);
573 auto &acc_sph = get_sink_acc_sph<Tvec>(sync);
574 auto &acc_ext = get_sink_acc_ext<Tvec>(sync);
576 for (
size_t i = 0; i < vel.size(); i++) {
577 vel[i] += (dt / 2) * (acc_sph[i] + acc_ext[i]);
581template<
class Tvec,
template<
class>
class SPHKernel>
582void shammodels::sph::modules::SinkParticlesUpdate<Tvec, SPHKernel>::compute_sph_forces() {
586 Tscal gpart_mass = solver_config.gpart_mass;
588 auto &sync = scheduler().synchronized_data;
589 auto &pos = get_sink_pos<Tvec>(sync);
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);
598 Tscal G = solver_config.get_constant_G();
599 Tscal epsilon_grav = 1e-9;
602 using namespace shamrock::patch;
608 auto dev_sched = shamsys::instance::get_compute_scheduler_ptr();
611 std::vector<Tvec> result_acc_sinks{};
613 for (
size_t sink_id = 0; sink_id < pos.size(); sink_id++) {
615 Tvec sph_acc_sink = {};
617 scheduler().for_each_patchdata_nonempty(
624 Tscal sink_mass = mass[sink_id];
625 Tscal sink_racc = accretion_radius[sink_id];
626 Tvec sink_pos = pos[sink_id];
630 auto axyz_ext = buf_axyz_ext.get_write_access(depends_list);
631 auto axyz_sync = buf_sync_axyz.get_write_access(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];
640 Tvec delta = r_a - sink_pos;
641 Tscal d = sycl::length(delta);
643 Tvec force = G * delta / (d * d * d);
652 axyz_sync[id_a] = force * gpart_mass;
653 axyz_ext[id_a] += -force * sink_mass;
658 buf_axyz_ext.complete_event_state(e);
659 buf_sync_axyz.complete_event_state(e);
665 result_acc_sinks.push_back(sph_acc_sink);
668 std::vector<Tvec> gathered_result_acc_sinks{};
670 result_acc_sinks, gathered_result_acc_sinks, MPI_COMM_WORLD);
672 for (
size_t id_s = 0; id_s < pos.size(); id_s++) {
677 acc_sph[id_s] += gathered_result_acc_sinks[rid * pos.size() + id_s];
682template<
class Tvec,
template<
class>
class SPHKernel>
683void shammodels::sph::modules::SinkParticlesUpdate<Tvec, SPHKernel>::compute_ext_forces() {
687 auto &sync = scheduler().synchronized_data;
688 auto &pos = get_sink_pos<Tvec>(sync);
693 auto &mass = get_sink_mass<Tvec>(sync);
694 auto &acc_ext = get_sink_acc_ext<Tvec>(sync);
696 for (
size_t i = 0; i < pos.size(); i++) {
700 Tscal G = solver_config.get_constant_G();
701 Tscal epsilon_grav_sink = 1e-9;
703 for (
size_t i = 0; i < pos.size(); i++) {
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);
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.
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
void _impl_evaluate_internal()
evaluate the node
void _impl_evaluate_internal()
evaluate 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
void free_alloc()
Free allocated memory.
virtual std::string _impl_get_tex() const
get the tex of the node
void _impl_evaluate_internal()
evaluate 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.
Inode is node between data edges, takes multiple inputs, multiple outputs.
void evaluate()
Evaluate the node.
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...
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.
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...
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.
i32 world_size()
Gives the size of the MPI communicator.
namespace for math utility
namespace for the main framework
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.
Helpers to access SPH sink particles stored as SoA synchronized data edges.
#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.
Patch object that contain generic patch information.
u64 id_patch
unique key that identify the patch
Functions related to the MPI communicator.