Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
BasicSPHGhosts.hpp
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
10#pragma once
11
18
21#include "shambackends/vec.hpp"
34#include <utility>
35#include <variant>
36
37namespace shammodels::sph {
38
39 template<class vec>
41
42 using Tscal = shambase::VecComponent<vec>;
43
44 struct Free {};
45 struct Periodic {};
47 i32_3 shear_base;
48 i32_3 shear_dir;
49 Tscal shear_value;
50 Tscal shear_speed;
51 };
52
53 using Variant = std::variant<Free, Periodic, ShearingPeriodic>;
54 };
55
56 template<class vec>
57 class BasicSPHGhostHandler {
58
59 using CfgClass = BasicSPHGhostHandlerConfig<vec>;
60 using Config = typename CfgClass::Variant;
61
62 PatchScheduler &sched;
63 Config ghost_config;
64
65 public:
66 using flt = shambase::VecComponent<vec>;
67 static constexpr u32 dim = shambase::VectorProperties<vec>::dimension;
68 using per_index = sycl::vec<i32, dim>;
69
71 vec offset;
72 vec offset_speed;
73 per_index periodicity_index;
75 flt volume_ratio;
76 };
77
79 InterfaceBuildInfos build_infos;
80 sham::DeviceBuffer<u32> ids_interf;
81 f64 part_cnt_ratio;
82 };
83
85
86 std::shared_ptr<shamrock::patch::PatchDataLayerLayout> &xyzh_ghost_layout;
87
88 std::shared_ptr<shamrock::solvergraph::RankGetter> patch_rank_owner;
89
90 BasicSPHGhostHandler(
91 PatchScheduler &sched,
92 Config ghost_config,
93 std::shared_ptr<shamrock::solvergraph::RankGetter> patch_rank_owner,
94 std::shared_ptr<shamrock::patch::PatchDataLayerLayout> &xyzh_ghost_layout)
95 : sched(sched), ghost_config(ghost_config),
96 patch_rank_owner(std::move(patch_rank_owner)), xyzh_ghost_layout(xyzh_ghost_layout) {}
97
106 GeneratorMap find_interfaces(
107 SerialPatchTree<vec> &sptree,
108 shamrock::patch::PatchtreeField<flt> &int_range_max_tree,
109 shamrock::patch::PatchField<flt> &int_range_max);
110
118 GeneratorMap &&gen);
119
120 void gen_debug_patch_ghost(shambase::DistributedDataShared<InterfaceIdTable> &interf_info);
121
123
133 SerialPatchTree<vec> &sptree,
134 shamrock::patch::PatchtreeField<flt> &int_range_max_tree,
135 shamrock::patch::PatchField<flt> &int_range_max) {
136 StackEntry stack_loc{};
137
139 find_interfaces(sptree, int_range_max_tree, int_range_max));
140 }
141
158 template<class T>
161 std::function<T(u64, u64, InterfaceBuildInfos, sham::DeviceBuffer<u32> &, u32)> fct) {
162 StackEntry stack_loc{};
163
164 // clang-format off
165 return builder.template map<T>([&](u64 sender, u64 receiver, InterfaceIdTable &build_table) {
166 if (build_table.ids_interf.get_size() == 0) {
168 "their is an empty id table in the interface, it should have been removed");
169 }
170
171 return fct(
172 sender,
173 receiver,
174 build_table.build_infos,
175 build_table.ids_interf,
176 build_table.ids_interf.get_size());
177
178 });
179 // clang-format on
180 }
181
182 template<class T>
183 void modify_interface_native(
186 std::function<void(u64, u64, InterfaceBuildInfos, sham::DeviceBuffer<u32> &, u32, T &)>
187 fct) {
188 StackEntry stack_loc{};
189
190 struct Args {
191 u64 sender;
192 u64 receiver;
193 InterfaceIdTable &build_table;
194 };
195
196 std::vector<Args> vecarg;
197
198 // clang-format off
199 builder.for_each([&](u64 sender, u64 receiver, InterfaceIdTable &build_table) {
200 if (build_table.ids_interf.get_size() == 0) {
202 "their is an empty id table in the interface, it should have been removed");
203 }
204
205 vecarg.push_back({.sender = sender, .receiver = receiver, .build_table = build_table});
206 });
207 // clang-format on
208
209 u32 i = 0;
210 mod.for_each([&](u64 sender, u64 receiver, T &ref) {
211 InterfaceIdTable &build_table = vecarg[i].build_table;
212
213 fct(sender,
214 receiver,
215 build_table.build_infos,
216 build_table.ids_interf,
217 build_table.ids_interf.get_size(),
218 ref);
219
220 i++;
221 });
222 }
223
236 template<class T>
239 std::function<T(u64, u64, InterfaceBuildInfos, sycl::buffer<u32> &, u32)> gen_1,
240 std::function<void(u64, u64, InterfaceBuildInfos, sycl::buffer<u32> &, u32, T &)>
241 modif) {
242
243 StackEntry stack_loc{};
244
245 struct Args {
246 u64 sender;
247 u64 receiver;
248 InterfaceIdTable &build_table;
249 };
250
251 std::vector<Args> vecarg;
252
253 shambase::DistributedDataShared<T> ret = builder.template map<
254 T>([&](u64 sender, u64 receiver, InterfaceIdTable &build_table) {
255 if (!bool(build_table.ids_interf)) {
257 "their is an empty id table in the interface, it should have been removed");
258 }
259
260 vecarg.push_back(
261 {.sender = sender, .receiver = receiver, .build_table = build_table});
262
263 return gen_1(
264 sender,
265 receiver,
266 build_table.build_infos,
267 *build_table.ids_interf,
268 build_table.ids_interf->size());
269 });
270
271 u32 i = 0;
272 ret.for_each([&](u64 sender, u64 receiver, T &ref) {
273 InterfaceIdTable &build_table = vecarg[i].build_table;
274
275 modif(
276 sender,
277 receiver,
278 build_table.build_infos,
279 *build_table.ids_interf,
280 build_table.ids_interf->size(),
281 ref);
282
283 i++;
284 });
285
286 return ret;
287 }
288
290 // interface generation/communication utility //////////////////////////////////////////////
292
294 build_position_interf_field(shambase::DistributedDataShared<InterfaceIdTable> &builder) {
295 StackEntry stack_loc{};
296
297 const u32 ihpart = sched.pdl_old().template get_field_idx<flt>("hpart");
298
300 builder,
301 [&](u64 sender,
302 u64 /*receiver*/,
303 InterfaceBuildInfos binfo,
305 u32 cnt) {
306 using namespace shamrock::patch;
307
308 PatchDataLayer &sender_pdat = sched.patch_data.get_pdat(sender);
309
310 shamrock::patch::PatchDataLayer ret(xyzh_ghost_layout);
311
312 sender_pdat.get_field<vec>(0).append_subset_to(
313 buf_idx, cnt, ret.get_field<vec>(0));
314 sender_pdat.get_field<flt>(ihpart).append_subset_to(
315 buf_idx, cnt, ret.get_field<flt>(1));
316
317 ret.get_field<vec>(0).apply_offset(binfo.offset);
318
319 return ret;
320 });
321 }
322
323 inline shambase::DistributedDataShared<shamrock::patch::PatchDataLayer> communicate_pdat(
324 const std::shared_ptr<shamrock::patch::PatchDataLayerLayout> &pdl_ptr,
325 shambase::DistributedDataShared<shamrock::patch::PatchDataLayer> &&interf,
326 std::shared_ptr<shamrock::solvergraph::ExchangeGhostLayer> exchange_gz_node,
327 bool show_debug_infos) {
328 StackEntry stack_loc{};
329
330 // ----------------------------------------------------------------------------------------
331 // temporary wrapper to slowly migrate to the new solvergraph
332 std::shared_ptr<shamrock::solvergraph::PatchDataLayerDDShared> exchange_gz_edge
333 = std::make_shared<shamrock::solvergraph::PatchDataLayerDDShared>("", "");
334
335 exchange_gz_edge->patchdatas
336 = std::forward<shambase::DistributedDataShared<shamrock::patch::PatchDataLayer>>(
337 interf);
338
339 if (show_debug_infos) {
340 std::shared_ptr<shamrock::solvergraph::ScalarsEdge<u64>> object_counts
341 = std::make_shared<shamrock::solvergraph::ScalarsEdge<u64>>(
342 "object_counts", "object_counts");
343 sched.for_each_patchdata_nonempty(
344 [&](const shamrock::patch::Patch p, shamrock::patch::PatchDataLayer &pdat) {
345 object_counts->values.add_obj(p.id_patch, pdat.get_obj_cnt());
346 });
347 auto exchange_gz_node_debug
348 = std::make_shared<shamrock::solvergraph::ExchangeGhostLayerDebugDotGraph>();
349 exchange_gz_node_debug->set_edges(object_counts, exchange_gz_edge);
350 exchange_gz_node_debug->evaluate();
351 }
352
353 exchange_gz_node->set_edges(this->patch_rank_owner, exchange_gz_edge);
354
355 exchange_gz_node->evaluate();
356
357 // ----------------------------------------------------------------------------------------
358
359 shambase::DistributedDataShared<shamrock::patch::PatchDataLayer> recv_dat;
360
361#if false
362 shamalgs::collective::serialize_sparse_comm<shamrock::patch::PatchDataLayer>(
363 shamsys::instance::get_compute_scheduler_ptr(),
364 std::forward<shambase::DistributedDataShared<shamrock::patch::PatchDataLayer>>(
365 interf),
366 recv_dat,
367 [&](u64 id) {
368 return sched.get_patch_rank_owner(id);
369 },
370 [](shamrock::patch::PatchDataLayer &pdat) {
371 shamalgs::SerializeHelper ser(shamsys::instance::get_compute_scheduler_ptr());
372 ser.allocate(pdat.serialize_buf_byte_size());
373 pdat.serialize_buf(ser);
374 return ser.finalize();
375 },
376 [&](sham::DeviceBuffer<u8> &&buf) {
377 // exchange the buffer held by the distrib data and give it to the serializer
378 shamalgs::SerializeHelper ser(
379 shamsys::instance::get_compute_scheduler_ptr(),
380 std::forward<sham::DeviceBuffer<u8>>(buf));
381 return shamrock::patch::PatchDataLayer::deserialize_buf(ser, pdl_ptr);
382 });
383#else
384 recv_dat = std::move(exchange_gz_edge->patchdatas);
385#endif
386
387 return recv_dat;
388 }
389
390 template<class T>
391 inline shambase::DistributedDataShared<PatchDataField<T>> communicate_pdatfield(
392 shambase::DistributedDataShared<PatchDataField<T>> &&interf,
393 u32 nvar,
394 std::shared_ptr<shamrock::solvergraph::ExchangeGhostField<T>> exchange_gz_node) {
395 StackEntry stack_loc{};
396
397 // ----------------------------------------------------------------------------------------
398 // temporary wrapper to slowly migrate to the new solvergraph
399 std::shared_ptr<shamrock::solvergraph::PatchDataFieldDDShared<T>> exchange_gz_edge
400 = std::make_shared<shamrock::solvergraph::PatchDataFieldDDShared<T>>("", "");
401
402 exchange_gz_edge->patchdata_fields
403 = std::forward<shambase::DistributedDataShared<PatchDataField<T>>>(interf);
404
405 exchange_gz_node->set_edges(this->patch_rank_owner, exchange_gz_edge);
406
407 exchange_gz_node->evaluate();
408
409 // ----------------------------------------------------------------------------------------
410
411 shambase::DistributedDataShared<PatchDataField<T>> recv_dat;
412
413#if false
414 shamalgs::collective::serialize_sparse_comm<PatchDataField<T>>(
415 shamsys::instance::get_compute_scheduler_ptr(),
416 std::forward<shambase::DistributedDataShared<PatchDataField<T>>>(interf),
417 recv_dat,
418 [&](u64 id) {
419 return sched.get_patch_rank_owner(id);
420 },
421 [](PatchDataField<T> &pdat) {
422 shamalgs::SerializeHelper ser(shamsys::instance::get_compute_scheduler_ptr());
423 ser.allocate(pdat.serialize_full_byte_size());
424 pdat.serialize_full(ser);
425 return ser.finalize();
426 },
427 [&](sham::DeviceBuffer<u8> &&buf) {
428 // exchange the buffer held by the distrib data and give it to the serializer
429 shamalgs::SerializeHelper ser(
430 shamsys::instance::get_compute_scheduler_ptr(),
431 std::forward<sham::DeviceBuffer<u8>>(buf));
433 });
434#else
435 recv_dat = std::move(exchange_gz_edge->patchdata_fields);
436#endif
437
438 return recv_dat;
439 }
440
441 inline shambase::DistributedDataShared<shamrock::patch::PatchDataLayer>
442 build_communicate_positions(
443 shambase::DistributedDataShared<InterfaceIdTable> &builder,
444 std::shared_ptr<shamrock::solvergraph::ExchangeGhostLayer> &exchange_gz_positions,
445 bool show_debug_infos) {
446 auto pos_interf = build_position_interf_field(builder);
447 return communicate_pdat(
448 xyzh_ghost_layout, std::move(pos_interf), exchange_gz_positions, show_debug_infos);
449 }
450
451 template<class T, class Tmerged>
452 inline shambase::DistributedData<Tmerged> merge_native(
453 shambase::DistributedDataShared<T> &&interfs,
454 std::function<
455 Tmerged(const shamrock::patch::Patch, shamrock::patch::PatchDataLayer &pdat)> init,
456 std::function<void(Tmerged &, T &)> appender) {
457
458 StackEntry stack_loc{};
459
460 shambase::DistributedData<Tmerged> merge_f;
461
462 sched.for_each_patchdata_nonempty(
463 [&](const shamrock::patch::Patch p, shamrock::patch::PatchDataLayer &pdat) {
464 Tmerged tmp_merge = init(p, pdat);
465
466 interfs.for_each([&](u64 sender, u64 receiver, T &interface) {
467 if (receiver == p.id_patch) {
468 appender(tmp_merge, interface);
469 }
470 });
471
472 merge_f.add_obj(p.id_patch, std::move(tmp_merge));
473 });
474
475 return merge_f;
476 }
477
478 inline shambase::DistributedData<shamrock::patch::PatchDataLayer> merge_position_buf(
479 shambase::DistributedDataShared<shamrock::patch::PatchDataLayer> &&positioninterfs) {
480 StackEntry stack_loc{};
481
482 const u32 ihpart = sched.pdl_old().template get_field_idx<flt>("hpart");
483
484 return merge_native<shamrock::patch::PatchDataLayer, shamrock::patch::PatchDataLayer>(
485 std::forward<shambase::DistributedDataShared<shamrock::patch::PatchDataLayer>>(
486 positioninterfs),
487 [=, this](const shamrock::patch::Patch p, shamrock::patch::PatchDataLayer &pdat) {
488 PatchDataField<vec> &pos = pdat.get_field<vec>(0);
489 PatchDataField<flt> &hpart = pdat.get_field<flt>(ihpart);
490
491 shamrock::patch::PatchDataLayer ret(xyzh_ghost_layout);
492
493 ret.get_field<vec>(0).insert(pos);
494 ret.get_field<flt>(1).insert(hpart);
495 ret.check_field_obj_cnt_match();
496
497 return ret;
498 },
499 [](shamrock::patch::PatchDataLayer &merged, shamrock::patch::PatchDataLayer &pint) {
500 merged.insert_elements(pint);
501
503 });
504 }
505
506 inline shambase::DistributedData<shamrock::patch::PatchDataLayer>
507 build_comm_merge_positions(
508 shambase::DistributedDataShared<InterfaceIdTable> &builder,
509 std::shared_ptr<shamrock::solvergraph::ExchangeGhostLayer> &exchange_gz_positions,
510 bool show_debug_infos) {
511 auto pos_interf = build_position_interf_field(builder);
512 return merge_position_buf(communicate_pdat(
513 xyzh_ghost_layout, std::move(pos_interf), exchange_gz_positions, show_debug_infos));
514 }
515 };
516
517} // namespace shammodels::sph
Solver graph node for exchanging ghost field data between distributed processes.
Solver graph node for exchanging ghost layer data between distributed processes.
Solver graph node for exchanging ghost layer data between distributed processes.
constexpr const char * hpart
Smoothing length field.
Header file describing a Node Instance.
Shared distributed data layer for patch data management in solver graphs.
MPI scheduler.
double f64
Alias for double.
std::uint32_t u32
32 bit unsigned integer
std::uint64_t u64
64 bit unsigned integer
static PatchDataField deserialize_full(shamalgs::SerializeHelper &serializer)
deserialize a field inverse of serialize_full
The MPI scheduler.
SchedulerPatchData patch_data
handle the data of the patches of the scheduler
A buffer allocated in USM (Unified Shared Memory).
size_t get_size() const
Gets the number of elements in the buffer.
Container for objects shared between two distributed data elements.
void for_each(std::function< void(u64, u64, T &)> &&f)
Apply a function to all stored objects.
iterator add_obj(u64 id, T &&obj)
Adds a new object to the collection.
shambase::DistributedDataShared< T > build_interface_native_stagged(shambase::DistributedDataShared< InterfaceIdTable > &builder, std::function< T(u64, u64, InterfaceBuildInfos, sycl::buffer< u32 > &, u32)> gen_1, std::function< void(u64, u64, InterfaceBuildInfos, sycl::buffer< u32 > &, u32, T &)> modif)
native handle to generate interfaces generate interfaces of type T (template arg) based on the provid...
CacheMap make_interface_cache(SerialPatchTree< vec > &sptree, shamrock::patch::PatchtreeField< flt > &int_range_max_tree, shamrock::patch::PatchField< flt > &int_range_max)
utility to generate both the metadata and index tables
shambase::DistributedDataShared< InterfaceIdTable > gen_id_table_interfaces(GeneratorMap &&gen)
precompute interfaces members and cache result in the return
shambase::DistributedDataShared< T > build_interface_native(shambase::DistributedDataShared< InterfaceIdTable > &builder, std::function< T(u64, u64, InterfaceBuildInfos, sham::DeviceBuffer< u32 > &, u32)> fct)
native handle to generate interfaces generate interfaces of type T (template arg) based on the provid...
GeneratorMap find_interfaces(SerialPatchTree< vec > &sptree, shamrock::patch::PatchtreeField< flt > &int_range_max_tree, shamrock::patch::PatchField< flt > &int_range_max)
Find interfaces and their metadata.
PatchDataLayer container class, the layout is described in patchdata_layout.
void check_field_obj_cnt_match()
check that all contained field have the same obj cnt
ExcptTypes make_except_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Create an exception with a message and a location.
namespace for the sph model
This file contains the definition for the stacktrace related functionality.
shambase::details::BasicStackEntry StackEntry
Alias for shambase::details::BasicStackEntry.