Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
Solver.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/assert.hpp"
20#include "shambase/memory.hpp"
22#include "shambase/string.hpp"
23#include "shambase/tabulate.hpp"
24#include "shambase/time.hpp"
32#include "shambackends/math.hpp"
33#include "shamcomm/logs.hpp"
35#include "shamcomm/wrapper.hpp"
85#include "shamphys/mhd.hpp"
113#include "shamsys/legacy/log.hpp"
117#include <memory>
118#include <stdexcept>
119#include <vector>
120
121template<class Tvec, template<class> class Kern>
123
124 PatchScheduler &sched = scheduler();
125
126 auto &sync_data = sched.synchronized_data;
127
128 shamrock::patch::PatchDataLayerLayout &pdl = scheduler().pdl_old();
129 bool has_B_field = solver_config.has_field_B_on_rho();
130 bool has_psi_field = solver_config.has_field_psi_on_ch();
131 bool has_epsilon_field = solver_config.dust_config.has_epsilon_field();
132 bool has_deltav_field = solver_config.dust_config.has_deltav_field();
133 bool has_s_j_field = solver_config.dust_config.has_s_j_field();
134
135 using namespace shamrock::solvergraph;
136
137 SolverGraph &solver_graph = storage.solver_graph;
138
139 solver_graph.register_edge(
140 "scheduler_patchdata", PatchDataLayerRefs("patchdatas", "\\mathbb{U}_{\\rm patch}"));
141 solver_graph.register_edge("part_counts", Indexes<u32>("Npart_patch", "N_{\\rm part}_p"));
142
143 solver_graph.register_edge("dt_half", IDataEdge<Tscal>("dt_half", "\\frac{dt}{2}"));
144 solver_graph.register_edge("gpart_mass", ScalarEdge<Tscal>("m", "m"));
145
146 solver_graph.register_edge("xyz", FieldRefs<Tvec>("xyz", "\\mathbf{r}"));
147 solver_graph.register_edge("vxyz", FieldRefs<Tvec>("vxyz", "\\mathbf{v}"));
148 solver_graph.register_edge("axyz", FieldRefs<Tvec>("axyz", "\\mathbf{a}"));
149 solver_graph.register_edge("uint", FieldRefs<Tscal>("uint", "u_{\\rm int}"));
150 solver_graph.register_edge("duint", FieldRefs<Tscal>("duint", "du_{\\rm int}"));
151 solver_graph.register_edge("hpart", FieldRefs<Tscal>("hpart", "h_{\\rm part}"));
152
153 if (has_B_field) {
154 solver_graph.register_edge("B/rho", FieldRefs<Tvec>("B/rho", "B_{\\rho}"));
155 solver_graph.register_edge("dB/rho", FieldRefs<Tvec>("dB/rho", "dB_{\\rho}"));
156 }
157 if (has_psi_field) {
158 solver_graph.register_edge("psi/ch", FieldRefs<Tscal>("psi/ch", "\\psi_{\\rm ch}"));
159 solver_graph.register_edge("dpsi/ch", FieldRefs<Tscal>("dpsi/ch", "d\\psi_{\\rm ch}"));
160 }
161 if (has_epsilon_field) {
162 solver_graph.register_edge("epsilon", FieldRefs<Tscal>("epsilon", "\\epsilon"));
163 solver_graph.register_edge("dtepsilon", FieldRefs<Tscal>("dtepsilon", "d\\epsilon"));
164 }
165 if (has_deltav_field) {
166 solver_graph.register_edge("deltav", FieldRefs<Tvec>("deltav", "\\Delta v"));
167 solver_graph.register_edge("dtdeltav", FieldRefs<Tvec>("dtdeltav", "d\\Delta v"));
168 }
169 if (has_s_j_field) {
170 solver_graph.register_edge("s_j", FieldRefs<Tscal>("s_j", "S_j"));
171 solver_graph.register_edge("ds_j_dt", FieldRefs<Tscal>("ds_j_dt", "dS_j/dt"));
172
173 u32 ndust = solver_config.dust_config.get_dust_nvar();
174 solver_graph.register_edge("Ts_j", Field<Tscal>(ndust, "Ts_j", "Ts_j"));
175 }
176
177 {
178 auto set_gpart_mass = solver_graph.register_node(
179 "set_gpart_mass", NodeSetEdge<ScalarEdge<Tscal>>([&](ScalarEdge<Tscal> &gpart_mass) {
180 gpart_mass.value = solver_config.gpart_mass;
181 }));
182 shambase::get_check_ref(set_gpart_mass)
183 .set_edges(solver_graph.get_edge_ptr<ScalarEdge<Tscal>>("gpart_mass"));
184 }
185
187 // attach fields to scheduler
189 {
190 std::vector<std::shared_ptr<shamrock::solvergraph::INode>> attach_field_sequence;
191
192 {
193 auto set_scheduler_patchdata = solver_graph.register_node(
194 "set_scheduler_patchdata",
195 NodeSetEdge<PatchDataLayerRefs>([&](PatchDataLayerRefs &scheduler_patchdata) {
196 scheduler_patchdata.free_alloc();
197 scheduler().for_each_patchdata_nonempty(
198 [&](const shamrock::patch::Patch &p,
200 scheduler_patchdata.patchdatas.add_obj(p.id_patch, std::ref(pdat));
201 });
202 }));
203 shambase::get_check_ref(set_scheduler_patchdata)
204 .set_edges(solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata"));
205 attach_field_sequence.push_back(set_scheduler_patchdata);
206 }
207
208 {
209 auto attach_part_counts
210 = solver_graph.register_node("attach_part_counts", GetObjCntFromLayer{});
211 shambase::get_check_ref(attach_part_counts)
212 .set_edges(
213 solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata"),
214 solver_graph.get_edge_ptr<Indexes<u32>>("part_counts"));
215 attach_field_sequence.push_back(attach_part_counts);
216 }
217
218 {
219 auto attach_xyz
220 = solver_graph.register_node("attach_xyz", GetFieldRefFromLayer<Tvec>(pdl, "xyz"));
221 shambase::get_check_ref(attach_xyz)
222 .set_edges(
223 solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata"),
224 solver_graph.get_edge_ptr<FieldRefs<Tvec>>("xyz"));
225 attach_field_sequence.push_back(attach_xyz);
226 }
227
228 {
229 auto attach_vxyz = solver_graph.register_node(
230 "attach_vxyz", GetFieldRefFromLayer<Tvec>(pdl, "vxyz"));
231 shambase::get_check_ref(attach_vxyz)
232 .set_edges(
233 solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata"),
234 solver_graph.get_edge_ptr<FieldRefs<Tvec>>("vxyz"));
235 attach_field_sequence.push_back(attach_vxyz);
236 }
237
238 {
239 auto attach_axyz = solver_graph.register_node(
240 "attach_axyz", GetFieldRefFromLayer<Tvec>(pdl, "axyz"));
241 shambase::get_check_ref(attach_axyz)
242 .set_edges(
243 solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata"),
244 solver_graph.get_edge_ptr<FieldRefs<Tvec>>("axyz"));
245 attach_field_sequence.push_back(attach_axyz);
246 }
247
248 {
249 auto attach_uint = solver_graph.register_node(
250 "attach_uint", GetFieldRefFromLayer<Tscal>(pdl, "uint"));
251 shambase::get_check_ref(attach_uint)
252 .set_edges(
253 solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata"),
254 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("uint"));
255 attach_field_sequence.push_back(attach_uint);
256 }
257
258 {
259 auto attach_duint = solver_graph.register_node(
260 "attach_duint", GetFieldRefFromLayer<Tscal>(pdl, "duint"));
261 shambase::get_check_ref(attach_duint)
262 .set_edges(
263 solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata"),
264 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("duint"));
265 attach_field_sequence.push_back(attach_duint);
266 }
267
268 {
269 auto attach_hpart = solver_graph.register_node(
270 "attach_hpart", GetFieldRefFromLayer<Tscal>(pdl, "hpart"));
271 shambase::get_check_ref(attach_hpart)
272 .set_edges(
273 solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata"),
274 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("hpart"));
275 attach_field_sequence.push_back(attach_hpart);
276 }
277
278 if (has_B_field) {
279 auto attach_B_on_rho = solver_graph.register_node(
280 "attach_B_on_rho", GetFieldRefFromLayer<Tvec>(pdl, "B/rho"));
281 shambase::get_check_ref(attach_B_on_rho)
282 .set_edges(
283 solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata"),
284 solver_graph.get_edge_ptr<FieldRefs<Tvec>>("B/rho"));
285 attach_field_sequence.push_back(attach_B_on_rho);
286 }
287
288 if (has_B_field) {
289 auto attach_dB_on_rho = solver_graph.register_node(
290 "attach_dB_on_rho", GetFieldRefFromLayer<Tvec>(pdl, "dB/rho"));
291 shambase::get_check_ref(attach_dB_on_rho)
292 .set_edges(
293 solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata"),
294 solver_graph.get_edge_ptr<FieldRefs<Tvec>>("dB/rho"));
295 attach_field_sequence.push_back(attach_dB_on_rho);
296 }
297
298 if (has_psi_field) {
299 auto attach_psi_on_ch = solver_graph.register_node(
300 "attach_psi_on_ch", GetFieldRefFromLayer<Tscal>(pdl, "psi/ch"));
301 shambase::get_check_ref(attach_psi_on_ch)
302 .set_edges(
303 solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata"),
304 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("psi/ch"));
305 attach_field_sequence.push_back(attach_psi_on_ch);
306 }
307
308 if (has_psi_field) {
309 auto attach_dpsi_on_ch = solver_graph.register_node(
310 "attach_dpsi_on_ch", GetFieldRefFromLayer<Tscal>(pdl, "dpsi/ch"));
311 shambase::get_check_ref(attach_dpsi_on_ch)
312 .set_edges(
313 solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata"),
314 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("dpsi/ch"));
315 attach_field_sequence.push_back(attach_dpsi_on_ch);
316 }
317
318 if (has_epsilon_field) {
319 auto attach_epsilon = solver_graph.register_node(
320 "attach_epsilon", GetFieldRefFromLayer<Tscal>(pdl, "epsilon"));
321 shambase::get_check_ref(attach_epsilon)
322 .set_edges(
323 solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata"),
324 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("epsilon"));
325 attach_field_sequence.push_back(attach_epsilon);
326 }
327
328 if (has_epsilon_field) {
329 auto attach_dtepsilon = solver_graph.register_node(
330 "attach_dtepsilon", GetFieldRefFromLayer<Tscal>(pdl, "dtepsilon"));
331 shambase::get_check_ref(attach_dtepsilon)
332 .set_edges(
333 solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata"),
334 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("dtepsilon"));
335 attach_field_sequence.push_back(attach_dtepsilon);
336 }
337
338 if (has_deltav_field) {
339 auto attach_deltav = solver_graph.register_node(
340 "attach_deltav", GetFieldRefFromLayer<Tvec>(pdl, "deltav"));
341 shambase::get_check_ref(attach_deltav)
342 .set_edges(
343 solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata"),
344 solver_graph.get_edge_ptr<FieldRefs<Tvec>>("deltav"));
345 attach_field_sequence.push_back(attach_deltav);
346 }
347
348 if (has_deltav_field) {
349 auto attach_dtdeltav = solver_graph.register_node(
350 "attach_dtdeltav", GetFieldRefFromLayer<Tvec>(pdl, "dtdeltav"));
351 shambase::get_check_ref(attach_dtdeltav)
352 .set_edges(
353 solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata"),
354 solver_graph.get_edge_ptr<FieldRefs<Tvec>>("dtdeltav"));
355 attach_field_sequence.push_back(attach_dtdeltav);
356 }
357
358 if (has_s_j_field) {
359 auto attach_s_j
360 = solver_graph.register_node("attach_s_j", GetFieldRefFromLayer<Tscal>(pdl, "s_j"));
361 shambase::get_check_ref(attach_s_j)
362 .set_edges(
363 solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata"),
364 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("s_j"));
365 attach_field_sequence.push_back(attach_s_j);
366 }
367
368 if (has_s_j_field) {
369 auto attach_ds_j_dt = solver_graph.register_node(
370 "attach_ds_j_dt", GetFieldRefFromLayer<Tscal>(pdl, "ds_j_dt"));
371 shambase::get_check_ref(attach_ds_j_dt)
372 .set_edges(
373 solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata"),
374 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("ds_j_dt"));
375 attach_field_sequence.push_back(attach_ds_j_dt);
376 }
377 solver_graph.register_node(
378 "attach fields to scheduler",
379 OperationSequence("attach fields", std::move(attach_field_sequence)));
380 }
381
383 // leapfrog predictor
385
386 {
387
388 auto make_half_step_sequence = [&](std::string prefix) {
389 std::vector<std::shared_ptr<shamrock::solvergraph::INode>> half_step_sequence;
390
391 {
392 auto half_step_vxyz = solver_graph.register_node(
394 shambase::get_check_ref(half_step_vxyz)
395 .set_edges(
396 solver_graph.get_edge_ptr<IDataEdge<Tscal>>("dt_half"),
397 solver_graph.get_edge_ptr<FieldRefs<Tvec>>("axyz"),
398 solver_graph.get_edge_ptr<Indexes<u32>>("part_counts"),
399 solver_graph.get_edge_ptr<FieldRefs<Tvec>>("vxyz"));
400 half_step_sequence.push_back(half_step_vxyz);
401 }
402
403 {
404 auto half_step_uint = solver_graph.register_node(
406 shambase::get_check_ref(half_step_uint)
407 .set_edges(
408 solver_graph.get_edge_ptr<IDataEdge<Tscal>>("dt_half"),
409 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("duint"),
410 solver_graph.get_edge_ptr<Indexes<u32>>("part_counts"),
411 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("uint"));
412 half_step_sequence.push_back(half_step_uint);
413 }
414
415 if (has_B_field) {
416 auto half_step_B_on_rho = solver_graph.register_node(
418 shambase::get_check_ref(half_step_B_on_rho)
419 .set_edges(
420 solver_graph.get_edge_ptr<IDataEdge<Tscal>>("dt_half"),
421 solver_graph.get_edge_ptr<FieldRefs<Tvec>>("dB/rho"),
422 solver_graph.get_edge_ptr<Indexes<u32>>("part_counts"),
423 solver_graph.get_edge_ptr<FieldRefs<Tvec>>("B/rho"));
424 half_step_sequence.push_back(half_step_B_on_rho);
425 }
426
427 if (has_psi_field) {
428 auto half_step_psi_on_ch = solver_graph.register_node(
429 prefix + "_psi_on_ch", shammodels::common::modules::ForwardEuler<Tscal>{});
430 shambase::get_check_ref(half_step_psi_on_ch)
431 .set_edges(
432 solver_graph.get_edge_ptr<IDataEdge<Tscal>>("dt_half"),
433 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("dpsi/ch"),
434 solver_graph.get_edge_ptr<Indexes<u32>>("part_counts"),
435 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("psi/ch"));
436 half_step_sequence.push_back(half_step_psi_on_ch);
437 }
438
439 if (has_epsilon_field) {
440 auto half_step_epsilon = solver_graph.register_node(
442 shambase::get_check_ref(half_step_epsilon)
443 .set_edges(
444 solver_graph.get_edge_ptr<IDataEdge<Tscal>>("dt_half"),
445 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("dtepsilon"),
446 solver_graph.get_edge_ptr<Indexes<u32>>("part_counts"),
447 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("epsilon"));
448 half_step_sequence.push_back(half_step_epsilon);
449 }
450
451 if (has_deltav_field) {
452 auto half_step_deltav = solver_graph.register_node(
454 shambase::get_check_ref(half_step_deltav)
455 .set_edges(
456 solver_graph.get_edge_ptr<IDataEdge<Tscal>>("dt_half"),
457 solver_graph.get_edge_ptr<FieldRefs<Tvec>>("dtdeltav"),
458 solver_graph.get_edge_ptr<Indexes<u32>>("part_counts"),
459 solver_graph.get_edge_ptr<FieldRefs<Tvec>>("deltav"));
460 half_step_sequence.push_back(half_step_deltav);
461 }
462
463 if (has_s_j_field) {
464 u32 ndust = solver_config.dust_config.get_dust_nvar();
465
466 auto &cfg = solver_config.dust_config.get_monofluid_tva();
467
468 if (cfg.ensure_s_j_positivity) {
469 auto half_step_s_j = solver_graph.register_node(
470 prefix + "_s_j",
472 shambase::get_check_ref(half_step_s_j)
473 .set_edges(
474 solver_graph.get_edge_ptr<IDataEdge<Tscal>>("dt_half"),
475 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("ds_j_dt"),
476 solver_graph.get_edge_ptr<Indexes<u32>>("part_counts"),
477 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("s_j"));
478 half_step_sequence.push_back(half_step_s_j);
479 } else {
480 auto half_step_s_j = solver_graph.register_node(
482 shambase::get_check_ref(half_step_s_j)
483 .set_edges(
484 solver_graph.get_edge_ptr<IDataEdge<Tscal>>("dt_half"),
485 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("ds_j_dt"),
486 solver_graph.get_edge_ptr<Indexes<u32>>("part_counts"),
487 solver_graph.get_edge_ptr<FieldRefs<Tscal>>("s_j"));
488 half_step_sequence.push_back(half_step_s_j);
489 }
490 }
491
492 return OperationSequence("half step", std::move(half_step_sequence));
493 };
494
495 solver_graph.register_node("half_step1", make_half_step_sequence("half_step1"));
496 solver_graph.register_node("half_step2", make_half_step_sequence("half_step2"));
497
498 {
499 auto full_step_xyz = solver_graph.register_node(
501 shambase::get_check_ref(full_step_xyz)
502 .set_edges(
503 sync_data.get_edge_ptr<IDataEdge<Tscal>>("dt"),
504 solver_graph.get_edge_ptr<FieldRefs<Tvec>>("vxyz"),
505 solver_graph.get_edge_ptr<Indexes<u32>>("part_counts"),
506 solver_graph.get_edge_ptr<FieldRefs<Tvec>>("xyz"));
507 }
508
509 {
510 auto leapfrog_predictor = solver_graph.register_node(
511 "leapfrog predictor",
513 "leapfrog predictor",
514 {
515 solver_graph.get_node_ptr_base("half_step1"),
516 solver_graph.get_node_ptr_base("full_step_xyz"),
517 solver_graph.get_node_ptr_base("half_step2"),
518 }));
519 }
520 }
521
523 // Part killing step
525 bool do_part_killing_step = solver_config.particle_killing.kill_list.size() > 0;
526
527 if (do_part_killing_step) {
528
529 auto patchdatas = solver_graph.get_edge_ptr<PatchDataLayerRefs>("scheduler_patchdata");
530 auto xyz_edge = solver_graph.get_edge_ptr<FieldRefs<Tvec>>("xyz");
531
532 auto part_to_remove = solver_graph.register_edge(
533 "part_to_remove", DistributedBuffers<u32>("part_to_remove", "part_to_remove"));
534
535 std::vector<std::shared_ptr<shamrock::solvergraph::INode>> part_kill_sequence{};
536
537 {
538
539 auto empty_part_to_remove
540 = solver_graph.register_node("empty_part_to_remove", NodeFreeAlloc{});
541 shambase::get_check_ref(empty_part_to_remove).set_edges(part_to_remove);
542 part_kill_sequence.push_back(empty_part_to_remove);
543 }
544
545 using kill_t = typename ParticleKillingConfig<Tvec>::kill_t;
546 using kill_sphere = typename ParticleKillingConfig<Tvec>::Sphere;
547
548 // selectors
549 for (kill_t &kill_obj : solver_config.particle_killing.kill_list) {
550 if (kill_sphere *kill_info = std::get_if<kill_sphere>(&kill_obj)) {
551
553 kill_info->center, kill_info->radius);
554 node_selector.set_edges(xyz_edge, part_to_remove);
555
556 part_kill_sequence.push_back(
557 std::make_shared<decltype(node_selector)>(std::move(node_selector)));
558 }
559 }
560
561 { // killing
562 modules::KillParticles node_killer{};
563 node_killer.set_edges(part_to_remove, patchdatas);
564
565 part_kill_sequence.push_back(
566 std::make_shared<decltype(node_killer)>(std::move(node_killer)));
567 }
568
569 solver_graph.register_node(
570 "part killing step",
571 OperationSequence("part killing step", std::move(part_kill_sequence)));
572 }
573
574 {
575 auto dt_to_half_dt = solver_graph.register_node(
576 "dt_to_half_dt",
578 [](const IDataEdge<Tscal> &dt, IDataEdge<Tscal> &half_dt) {
579 half_dt.data = dt.data / 2;
580 }});
581 shambase::get_check_ref(dt_to_half_dt)
582 .set_edges(
583 sync_data.get_edge_ptr<IDataEdge<Tscal>>("dt"),
584 solver_graph.get_edge_ptr<IDataEdge<Tscal>>("dt_half"));
585 }
586
587 {
588 std::vector<std::shared_ptr<shamrock::solvergraph::INode>> seq{};
589
590 seq.push_back(solver_graph.get_node_ptr_base("dt_to_half_dt"));
591 seq.push_back(solver_graph.get_node_ptr_base("set_gpart_mass"));
592 seq.push_back(solver_graph.get_node_ptr_base("attach fields to scheduler"));
593 seq.push_back(solver_graph.get_node_ptr_base("leapfrog predictor"));
594 if (do_part_killing_step) {
595 seq.push_back(solver_graph.get_node_ptr_base("part killing step"));
596 }
597
598 storage.solver_sequence = solver_graph.register_node(
599 "time_step", OperationSequence("time step", std::move(seq)));
600 }
601
602 storage.part_counts
603 = std::make_shared<shamrock::solvergraph::Indexes<u32>>("part_counts", "N_{\\rm part}");
604
605 storage.part_counts_with_ghost = std::make_shared<shamrock::solvergraph::Indexes<u32>>(
606 "part_counts_with_ghost", "N_{\\rm part, with ghost}");
607
608 storage.patch_rank_owner = std::make_shared<shamrock::solvergraph::RankGetter>(
609 [&](u64 patch_id) -> u32 {
610 return scheduler().get_patch_rank_owner(patch_id);
611 },
612 "patch_rank_owner",
613 "rank");
614
615 // merged ghost spans
616 storage.positions_with_ghosts
617 = std::make_shared<shamrock::solvergraph::FieldRefs<Tvec>>("part_pos", "\\mathbf{r}");
618 storage.hpart_with_ghosts
619 = std::make_shared<shamrock::solvergraph::FieldRefs<Tscal>>("h_part", "h");
620
621 storage.neigh_cache
622 = std::make_shared<shammodels::sph::solvergraph::NeighCache>("neigh_cache", "neigh");
623
624 storage.omega = std::make_shared<shamrock::solvergraph::Field<Tscal>>(1, "omega", "\\Omega");
625
626 if (solver_config.has_field_alphaAV()) {
627 storage.alpha_av_updated = std::make_shared<shamrock::solvergraph::Field<Tscal>>(
628 1, "alpha_av_updated", "\\alpha_{\\rm AV}");
629 }
630
631 storage.pressure = std::make_shared<shamrock::solvergraph::Field<Tscal>>(1, "pressure", "P");
632 storage.soundspeed
633 = std::make_shared<shamrock::solvergraph::Field<Tscal>>(1, "soundspeed", "c_s");
634
635 storage.exchange_gz_alpha
636 = std::make_shared<shamrock::solvergraph::ExchangeGhostField<Tscal>>();
637 storage.exchange_gz_node
638 = std::make_shared<shamrock::solvergraph::ExchangeGhostLayer>(storage.ghost_layout);
639 storage.exchange_gz_positions
640 = std::make_shared<shamrock::solvergraph::ExchangeGhostLayer>(storage.xyzh_ghost_layout);
641}
642
643template<class Tvec, template<class> class Kern>
645 std::string filename, bool add_patch_world_id) {
646
647 modules::VTKDump(context, solver_config).do_dump(filename, add_patch_world_id);
648}
649
651// Debug interface dump
653
654namespace shammodels::sph {
655
656 template<class Tvec>
658 using Tscal = shambase::VecComponent<Tvec>;
659
660 u64 nobj;
661 f64 gpart_mass;
662
663 sycl::buffer<Tvec> &buf_xyz;
664 sycl::buffer<Tscal> &buf_hpart;
665 sycl::buffer<Tvec> &buf_vxyz;
666 };
667
668 template<class Tvec>
669 void fill_blocks(PhantomDumpBlock &block, Debug_ph_dump<Tvec> &info) {
670
671 using Tscal = shambase::VecComponent<Tvec>;
672 std::vector<Tvec> xyz = shamalgs::memory::buf_to_vec(info.buf_xyz, info.nobj);
673
674 u64 xid = block.get_ref_fort_real("x");
675 u64 yid = block.get_ref_fort_real("y");
676 u64 zid = block.get_ref_fort_real("z");
677
678 for (auto vec : xyz) {
679 block.blocks_fort_real[xid].vals.push_back(vec.x());
680 block.blocks_fort_real[yid].vals.push_back(vec.y());
681 block.blocks_fort_real[zid].vals.push_back(vec.z());
682 }
683
684 std::vector<Tscal> h = shamalgs::memory::buf_to_vec(info.buf_hpart, info.nobj);
685 u64 hid = block.get_ref_f32("h");
686 for (auto h_ : h) {
687 block.blocks_f32[hid].vals.push_back(h_);
688 }
689
690 std::vector<Tvec> vxyz = shamalgs::memory::buf_to_vec(info.buf_vxyz, info.nobj);
691
692 u64 vxid = block.get_ref_fort_real("vx");
693 u64 vyid = block.get_ref_fort_real("vy");
694 u64 vzid = block.get_ref_fort_real("vz");
695
696 for (auto vec : vxyz) {
697 block.blocks_fort_real[vxid].vals.push_back(vec.x());
698 block.blocks_fort_real[vyid].vals.push_back(vec.y());
699 block.blocks_fort_real[vzid].vals.push_back(vec.z());
700 }
701
702 block.tot_count = block.blocks_fort_real[xid].vals.size();
703 }
704
705 template<class Tvec>
706 shammodels::sph::PhantomDump make_interface_debug_phantom_dump(Debug_ph_dump<Tvec> info) {
707
708 using Tscal = shambase::VecComponent<Tvec>;
709 PhantomDump dump;
710
712 dump.iversion = 1;
713 dump.fileid = shambase::format("{:100s}", "FT:Phantom Shamrock writer");
714
715 u32 Ntot = info.nobj;
716 dump.table_header_fort_int.add("nparttot", Ntot);
717 dump.table_header_fort_int.add("ntypes", 8);
718 dump.table_header_fort_int.add("npartoftype", Ntot);
719 dump.table_header_fort_int.add("npartoftype", 0);
720 dump.table_header_fort_int.add("npartoftype", 0);
721 dump.table_header_fort_int.add("npartoftype", 0);
722 dump.table_header_fort_int.add("npartoftype", 0);
723 dump.table_header_fort_int.add("npartoftype", 0);
724 dump.table_header_fort_int.add("npartoftype", 0);
725 dump.table_header_fort_int.add("npartoftype", 0);
726
727 dump.table_header_i64.add("nparttot", Ntot);
728 dump.table_header_i64.add("ntypes", 8);
729 dump.table_header_i64.add("npartoftype", Ntot);
730 dump.table_header_i64.add("npartoftype", 0);
731 dump.table_header_i64.add("npartoftype", 0);
732 dump.table_header_i64.add("npartoftype", 0);
733 dump.table_header_i64.add("npartoftype", 0);
734 dump.table_header_i64.add("npartoftype", 0);
735 dump.table_header_i64.add("npartoftype", 0);
736 dump.table_header_i64.add("npartoftype", 0);
737
738 dump.table_header_fort_int.add("nblocks", 1);
739 dump.table_header_fort_int.add("nptmass", 0);
740 dump.table_header_fort_int.add("ndustlarge", 0);
741 dump.table_header_fort_int.add("ndustsmall", 0);
742 dump.table_header_fort_int.add("idust", 7);
743 dump.table_header_fort_int.add("idtmax_n", 1);
744 dump.table_header_fort_int.add("idtmax_frac", 0);
745 dump.table_header_fort_int.add("idumpfile", 0);
746 dump.table_header_fort_int.add("majorv", 2023);
747 dump.table_header_fort_int.add("minorv", 0);
748 dump.table_header_fort_int.add("microv", 0);
749 dump.table_header_fort_int.add("isink", 0);
750
751 dump.table_header_i32.add("iexternalforce", 0);
752 dump.table_header_i32.add("ieos", 2);
753 dump.table_header_fort_real.add("gamma", 1.66667);
754 dump.table_header_fort_real.add("RK2", 0);
755 dump.table_header_fort_real.add("polyk2", 0);
756 dump.table_header_fort_real.add("qfacdisc", 0.75);
757 dump.table_header_fort_real.add("qfacdisc2", 0.75);
758
759 dump.table_header_fort_real.add("time", 0);
760 dump.table_header_fort_real.add("dtmax", 0.1);
761
762 dump.table_header_fort_real.add("rhozero", 0);
763 dump.table_header_fort_real.add("hfact", 1.2);
764 dump.table_header_fort_real.add("tolh", 0.0001);
765 dump.table_header_fort_real.add("C_cour", 0);
766 dump.table_header_fort_real.add("C_force", 0);
767 dump.table_header_fort_real.add("alpha", 0);
768 dump.table_header_fort_real.add("alphau", 1);
769 dump.table_header_fort_real.add("alphaB", 1);
770
771 dump.table_header_fort_real.add("massoftype", info.gpart_mass);
772 dump.table_header_fort_real.add("massoftype", 0);
773 dump.table_header_fort_real.add("massoftype", 0);
774 dump.table_header_fort_real.add("massoftype", 0);
775 dump.table_header_fort_real.add("massoftype", 0);
776 dump.table_header_fort_real.add("massoftype", 0);
777 dump.table_header_fort_real.add("massoftype", 0);
778 dump.table_header_fort_real.add("massoftype", 0);
779
780 dump.table_header_fort_real.add("Bextx", 0);
781 dump.table_header_fort_real.add("Bexty", 0);
782 dump.table_header_fort_real.add("Bextz", 0);
783 dump.table_header_fort_real.add("dum", 0);
784
785 dump.table_header_fort_real.add("get_conserv", -1);
786 dump.table_header_fort_real.add("etot_in", 0.59762);
787 dump.table_header_fort_real.add("angtot_in", 0.0189694);
788 dump.table_header_fort_real.add("totmom_in", 0.0306284);
789
790 dump.table_header_f64.add("udist", 1);
791 dump.table_header_f64.add("umass", 1);
792 dump.table_header_f64.add("utime", 1);
793 dump.table_header_f64.add("umagfd", 3.54491);
794
795 PhantomDumpBlock block_part;
796
797 fill_blocks(block_part, info);
798
799 dump.blocks.push_back(std::move(block_part));
800
801 return dump;
802 }
803
804} // namespace shammodels::sph
805
806template<class Tvec, template<class> class Kern>
807void shammodels::sph::Solver<Tvec, Kern>::gen_serial_patch_tree() {
808 StackEntry stack_loc{};
809
810 SerialPatchTree<Tvec> _sptree = SerialPatchTree<Tvec>::build(scheduler());
811 _sptree.attach_buf();
812 storage.serial_patch_tree.set(std::move(_sptree));
813}
814
820template<class Tvec, template<class> class Kern>
822
823 StackEntry stack_loc{};
824
825 shamlog_debug_ln("SphSolver", "apply position boundary");
826
827 PatchScheduler &sched = scheduler();
828
829 shamrock::SchedulerUtility integrators(sched);
831
832 auto &pdl = sched.pdl_old();
833
834 const u32 ixyz = pdl.get_field_idx<Tvec>("xyz");
835 const u32 ivxyz = pdl.get_field_idx<Tvec>("vxyz");
836 auto [bmin, bmax] = sched.get_box_volume<Tvec>();
837
838 using SolverConfigBC = typename Config::BCConfig;
839 using SolverBCFree = typename SolverConfigBC::Free;
840 using SolverBCPeriodic = typename SolverConfigBC::Periodic;
841 using SolverBCShearingPeriodic = typename SolverConfigBC::ShearingPeriodic;
842 if (SolverBCFree *c = std::get_if<SolverBCFree>(&solver_config.boundary_config.config)) {
843 if (shamcomm::world_rank() == 0) {
844 logger::info_ln("PositionUpdated", "free boundaries skipping geometry update");
845 }
846 } else if (
847 SolverBCPeriodic *c
848 = std::get_if<SolverBCPeriodic>(&solver_config.boundary_config.config)) {
849 integrators.fields_apply_periodicity(ixyz, std::pair{bmin, bmax});
850 } else if (
851 SolverBCShearingPeriodic *c
852 = std::get_if<SolverBCShearingPeriodic>(&solver_config.boundary_config.config)) {
853 integrators.fields_apply_shearing_periodicity(
854 ixyz,
855 ivxyz,
856 std::pair{bmin, bmax},
857 c->shear_base,
858 c->shear_dir,
859 c->shear_speed * time_val,
860 c->shear_speed);
861 }
862
863 reatrib.reatribute_patch_objects(storage.serial_patch_tree.get(), "xyz");
864}
865
866template<class Tvec, template<class> class Kern>
868
869 StackEntry stack_loc{};
870
871 using SPHUtils = sph::SPHUtilities<Tvec, Kernel>;
872 SPHUtils sph_utils(scheduler());
873
874 storage.ghost_patch_cache.set(sph_utils.build_interf_cache(
875 storage.ghost_handler.get(),
876 storage.serial_patch_tree.get(),
877 solver_config.htol_up_coarse_cycle));
878
879 // storage.ghost_handler.get().gen_debug_patch_ghost(storage.ghost_patch_cache.get());
880}
881
882template<class Tvec, template<class> class Kern>
884 StackEntry stack_loc{};
885 storage.ghost_patch_cache.reset();
886}
887
888template<class Tvec, template<class> class Kern>
890
891 StackEntry stack_loc{};
892
893 storage.merged_xyzh.set(storage.ghost_handler.get().build_comm_merge_positions(
894 storage.ghost_patch_cache.get(),
895 storage.exchange_gz_positions,
896 solver_config.show_ghost_zone_graph));
897
898 { // set element counts
899 shambase::get_check_ref(storage.part_counts).indexes
900 = storage.merged_xyzh.get().template map<u32>(
901 [&](u64 id, shamrock::patch::PatchDataLayer &mpdat) {
902 return scheduler().patch_data.get_pdat(id).get_obj_cnt();
903 });
904 }
905
906 { // set element counts
907 shambase::get_check_ref(storage.part_counts_with_ghost).indexes
908 = storage.merged_xyzh.get().template map<u32>(
909 [&](u64 id, shamrock::patch::PatchDataLayer &mpdat) {
910 return mpdat.get_obj_cnt();
911 });
912 }
913
914 { // Attach spans to block coords
915 shambase::get_check_ref(storage.positions_with_ghosts)
916 .set_refs(storage.merged_xyzh.get()
917 .template map<std::reference_wrapper<PatchDataField<Tvec>>>(
918 [&](u64 id, shamrock::patch::PatchDataLayer &mpdat) {
919 return std::ref(mpdat.get_field<Tvec>(0));
920 }));
921
922 shambase::get_check_ref(storage.hpart_with_ghosts)
923 .set_refs(storage.merged_xyzh.get()
924 .template map<std::reference_wrapper<PatchDataField<Tscal>>>(
925 [&](u64 id, shamrock::patch::PatchDataLayer &mpdat) {
926 return std::ref(mpdat.get_field<Tscal>(1));
927 }));
928 }
929}
930
931template<class Tvec, template<class> class Kern>
935
936template<class Tvec, template<class> class Kern>
938 StackEntry stack_loc{};
939 storage.merged_pos_trees.reset();
940}
941
942template<class Tvec, template<class> class Kern>
944 StackEntry stack_loc{};
945
946 using namespace shamrock;
947 using namespace shamrock::patch;
948
950 using SPHUtils = sph::SPHUtilities<Tvec, Kernel>;
951
952 SPHUtils sph_utils(scheduler());
953 shamrock::SchedulerUtility utility(scheduler());
954
955 PatchDataLayerLayout &pdl = scheduler().pdl_old();
956 const u32 ihpart = pdl.get_field_idx<Tscal>("hpart");
957
958 ComputeField<Tscal> _epsilon_h, _h_old;
959
960 auto should_set_omega_mask = std::make_shared<shamrock::solvergraph::Field<u32>>(
961 1, "should_set_omega_mask", "should_set_omega_mask");
962
963 u32 hstep_cnt = 0;
964 u32 hstep_max = solver_config.h_max_subcycles_count;
965 for (; hstep_cnt < hstep_max; hstep_cnt++) {
966
967 gen_ghost_handler(time_val + dt);
973
974 _epsilon_h = utility.make_compute_field<Tscal>("epsilon_h", 1, Tscal(100));
975 _h_old = utility.save_field<Tscal>(ihpart, "h_old");
976
977 Tscal max_eps_h;
978
979 if (solver_config.gpart_mass == 0) {
981 "invalid gpart_mass {}, this configuration can not converge.\n"
982 "Please set it using either model.set_particle_mass(pmass) or "
983 "cfg.set_particle_mass(pmass)",
984 solver_config.gpart_mass));
985 }
986
987 // sizes
988 std::shared_ptr<shamrock::solvergraph::Indexes<u32>> sizes
989 = std::make_shared<shamrock::solvergraph::Indexes<u32>>("", "");
990 scheduler().for_each_patchdata_nonempty([&](const Patch p, PatchDataLayer &pdat) {
991 sizes->indexes.add_obj(p.id_patch, pdat.get_obj_cnt());
992 });
993
994 // neigh cache
995 auto &neigh_cache = storage.neigh_cache;
996
997 // positions
998 auto &pos_merged = storage.positions_with_ghosts;
999
1000 // old smoothing length field
1001 std::shared_ptr<shamrock::solvergraph::FieldRefs<Tscal>> hold
1002 = std::make_shared<shamrock::solvergraph::FieldRefs<Tscal>>("", "");
1004 scheduler().for_each_patchdata_nonempty([&](const Patch p, PatchDataLayer &pdat) {
1005 auto &field = _h_old.get_field(p.id_patch);
1006 hold_refs.add_obj(p.id_patch, std::ref(field));
1007 });
1008 hold->set_refs(hold_refs);
1009
1010 // new smoothing length field
1011 std::shared_ptr<shamrock::solvergraph::FieldRefs<Tscal>> hnew
1012 = std::make_shared<shamrock::solvergraph::FieldRefs<Tscal>>("", "");
1014 scheduler().for_each_patchdata_nonempty([&](const Patch p, PatchDataLayer &pdat) {
1015 auto &field = pdat.get_field<Tscal>(ihpart);
1016 hnew_refs.add_obj(p.id_patch, std::ref(field));
1017 });
1018 hnew->set_refs(hnew_refs);
1019
1020 // epsilon field
1021 std::shared_ptr<shamrock::solvergraph::FieldRefs<Tscal>> eps_h
1022 = std::make_shared<shamrock::solvergraph::FieldRefs<Tscal>>("", "");
1024 scheduler().for_each_patchdata_nonempty([&](const Patch p, PatchDataLayer &pdat) {
1025 auto &field = _epsilon_h.get_field(p.id_patch);
1026 eps_h_refs.add_obj(p.id_patch, std::ref(field));
1027 });
1028 eps_h->set_refs(eps_h_refs);
1029
1030 std::shared_ptr<shamrock::solvergraph::INode> smth_h_iter_ptr;
1031
1032 using h_conf_density_based = typename SmoothingLengthConfig::DensityBased;
1033 using h_conf_neigh_lim = typename SmoothingLengthConfig::DensityBasedNeighLim;
1034
1035 if (h_conf_density_based *conf
1036 = std::get_if<h_conf_density_based>(&solver_config.smoothing_length_config.config)) {
1037 std::shared_ptr<shammodels::sph::modules::IterateSmoothingLengthDensity<Tvec, Kernel>>
1038 smth_h_iter = std::make_shared<
1040 solver_config.gpart_mass,
1041 solver_config.htol_up_coarse_cycle,
1042 solver_config.htol_up_fine_cycle);
1043 smth_h_iter->set_edges(sizes, neigh_cache, pos_merged, hold, hnew, eps_h);
1044 smth_h_iter_ptr = smth_h_iter;
1045 } else if (
1046 h_conf_neigh_lim *conf
1047 = std::get_if<h_conf_neigh_lim>(&solver_config.smoothing_length_config.config)) {
1048 std::shared_ptr<
1050 smth_h_iter_neigh_lim = std::make_shared<
1052 solver_config.gpart_mass,
1053 solver_config.htol_up_coarse_cycle,
1054 solver_config.htol_up_fine_cycle,
1055 conf->max_neigh_count);
1056 smth_h_iter_neigh_lim->set_edges(
1057 sizes, neigh_cache, pos_merged, hold, hnew, eps_h, should_set_omega_mask);
1058 smth_h_iter_ptr = smth_h_iter_neigh_lim;
1059 } else {
1060 shambase::throw_with_loc<std::runtime_error>("Invalid smoothing length configuration");
1061 }
1062 // iterate smoothing length
1063
1064 std::shared_ptr<shamrock::solvergraph::ScalarEdge<bool>> is_converged
1065 = std::make_shared<shamrock::solvergraph::ScalarEdge<bool>>("", "");
1066
1068 smth_h_iter_ptr, solver_config.epsilon_h, solver_config.h_iter_per_subcycles, false);
1069 loop_smth_h_iter.set_edges(eps_h, is_converged);
1070
1071 loop_smth_h_iter.evaluate();
1072
1073 if (!is_converged->value) {
1074
1075 Tscal largest_h = 0;
1076
1077 scheduler().for_each_patchdata_nonempty([&](const Patch p, PatchDataLayer &pdat) {
1078 largest_h = sham::max(largest_h, pdat.get_field<Tscal>(ihpart).compute_max());
1079 });
1080 Tscal global_largest_h = shamalgs::collective::allreduce_max(largest_h);
1081
1082 std::string add_info = "";
1083 u64 cnt_unconverged = 0;
1084 scheduler().for_each_patchdata_nonempty([&](const Patch p, PatchDataLayer &pdat) {
1085 auto res
1086 = _epsilon_h.get_field(p.id_patch).get_ids_buf_where([](auto access, u32 id) {
1087 return access[id] == -1;
1088 });
1089
1090 if (hstep_cnt == hstep_max - 1) {
1091 if (std::get<0>(res)) {
1092 add_info += "\n patch " + std::to_string(p.id_patch) + " ";
1093 add_info += "errored parts : \n";
1094 sycl::buffer<u32> &idx_err = *std::get<0>(res);
1095
1096 sham::DeviceBuffer<Tvec> &xyz = pdat.get_field_buf_ref<Tvec>(0);
1097 sham::DeviceBuffer<Tscal> &hpart = pdat.get_field_buf_ref<Tscal>(ihpart);
1098
1099 auto pos = xyz.copy_to_stdvec();
1100 auto h = hpart.copy_to_stdvec();
1101
1102 {
1103 sycl::host_accessor acc{idx_err};
1104 for (u32 i = 0; i < idx_err.size(); i++) {
1105 add_info += shambase::format(
1106 "{} - pos : {}, hpart : {}\n", acc[i], pos[acc[i]], h[acc[i]]);
1107 }
1108 }
1109 }
1110 }
1111
1112 cnt_unconverged += std::get<1>(res);
1113 });
1114
1115 u64 global_cnt_unconverged = shamalgs::collective::allreduce_sum(cnt_unconverged);
1116
1117 if (shamcomm::world_rank() == 0) {
1119 "Smoothinglength",
1120 "smoothing length is not converged, rerunning the iterator ...\n largest h "
1121 "=",
1122 global_largest_h,
1123 "unconverged cnt =",
1124 global_cnt_unconverged,
1125 add_info);
1126 }
1127
1128 reset_ghost_handler();
1130
1131 shambase::get_check_ref(storage.part_counts).free_alloc();
1132 shambase::get_check_ref(storage.part_counts_with_ghost).free_alloc();
1133 shambase::get_check_ref(storage.positions_with_ghosts).free_alloc();
1134 shambase::get_check_ref(storage.hpart_with_ghosts).free_alloc();
1135
1136 storage.merged_xyzh.reset();
1137
1141
1142 // scheduler().for_each_patchdata_nonempty([&](Patch cur_p, PatchData &pdat) {
1143 // pdat.synchronize_buf();
1144 // });
1145
1146 continue;
1147 }
1148
1149 // The hpart is not valid anymore in ghost zones since we iterated it's value
1150 shambase::get_check_ref(storage.hpart_with_ghosts).free_alloc();
1151
1152 _epsilon_h.reset();
1153 _h_old.reset();
1154 break;
1155 }
1156
1157 if (hstep_cnt == hstep_max) {
1158 logger::err_ln("SPH", "the h iterator is not converged after", hstep_cnt, "iterations");
1159 }
1160
1161 std::shared_ptr<shamrock::solvergraph::FieldRefs<Tscal>> hnew_edge
1162 = std::make_shared<shamrock::solvergraph::FieldRefs<Tscal>>("", "");
1164 scheduler().for_each_patchdata_nonempty([&](const Patch p, PatchDataLayer &pdat) {
1165 auto &field = pdat.get_field<Tscal>(ihpart);
1166 hnew_refs.add_obj(p.id_patch, std::ref(field));
1167 });
1168 hnew_edge->set_refs(hnew_refs);
1169
1170 modules::NodeComputeOmega<Tvec, Kern> compute_omega{solver_config.gpart_mass};
1171 compute_omega.set_edges(
1172 storage.part_counts,
1173 storage.neigh_cache,
1174 storage.positions_with_ghosts,
1175 hnew_edge,
1176 storage.omega);
1177 compute_omega.evaluate();
1178
1179 if (solver_config.smoothing_length_config.is_density_based_neigh_lim()) {
1180 // if the h limiter is triggered, omega does not hold it's sense of dh/dr anymore
1181 // so we set it to 1, this effectively is equivalent of disabling the energy correction
1182 // term corresponding to dh/dr
1183 modules::SetWhenMask<Tscal> set_omega_mask{1};
1184 set_omega_mask.set_edges(storage.part_counts, should_set_omega_mask, storage.omega);
1185 set_omega_mask.evaluate();
1186 }
1187}
1188
1189template<class Tvec, template<class> class Kern>
1191
1192 storage.ghost_layout = std::make_shared<shamrock::patch::PatchDataLayerLayout>();
1193
1195 = shambase::get_check_ref(storage.ghost_layout);
1196
1197 solver_config.set_ghost_layout(ghost_layout);
1198
1199 storage.xyzh_ghost_layout = std::make_shared<shamrock::patch::PatchDataLayerLayout>();
1200 storage.xyzh_ghost_layout->template add_field<Tvec>("xyz", 1);
1201 storage.xyzh_ghost_layout->template add_field<Tscal>("hpart", 1);
1202}
1203
1204template<class Tvec, template<class> class Kern>
1206
1207 StackEntry stack_loc{};
1208
1209 auto &xyzh_merged = storage.merged_xyzh.get();
1210 auto dev_sched = shamsys::instance::get_compute_scheduler_ptr();
1211
1212 storage.rtree_rint_field.set(
1213 storage.merged_pos_trees.get().template map<shamtree::KarrasRadixTreeField<Tscal>>(
1214 [&](u64 id, RTree &rtree) -> shamtree::KarrasRadixTreeField<Tscal> {
1215 shamrock::patch::PatchDataLayer &tmp = xyzh_merged.get(id);
1216 auto &buf = tmp.get_field_buf_ref<Tscal>(1);
1217 auto buf_int = shamtree::new_empty_karras_radix_tree_field<Tscal>();
1218
1219 auto ret = shamtree::compute_tree_field_max_field<Tscal>(
1220 rtree.structure,
1221 rtree.reduced_morton_set.get_leaf_cell_iterator(),
1222 std::move(buf_int),
1223 buf);
1224
1225 // the old tree used to increase the size of the hmax of the tree nodes by the
1226 // tolerance so we do it also with the new tree, maybe we should move that somewhere
1227 // else.
1228 sham::kernel_call(
1229 dev_sched->get_queue(),
1230 sham::MultiRef{},
1231 sham::MultiRef{ret.buf_field},
1232 ret.buf_field.get_size(),
1233 [htol = solver_config.htol_up_coarse_cycle](u32 i, Tscal *h_tree) {
1234 h_tree[i] *= htol;
1235 });
1236
1237 return std::move(ret);
1238 }));
1239}
1240
1241template<class Tvec, template<class> class Kern>
1243 storage.rtree_rint_field.reset();
1244}
1245
1246template<class Tvec, template<class> class Kern>
1248 if (solver_config.use_two_stage_search) {
1250 context, solver_config, storage)
1251 .start_neighbors_cache_2stages();
1252 } else {
1254 context, solver_config, storage)
1255 .start_neighbors_cache();
1256 }
1257
1258 if (solver_config.show_neigh_stats) {
1259 auto &pos_merged = storage.positions_with_ghosts;
1260 auto &neigh_cache = storage.neigh_cache;
1261 auto &hpart_with_ghosts = storage.hpart_with_ghosts;
1262 auto &part_counts = storage.part_counts;
1263
1264 modules::ComputeNeighStats<Tvec> compute_neigh_stats(Kernel::Rkern);
1265
1266 compute_neigh_stats.set_edges(part_counts, neigh_cache, pos_merged, hpart_with_ghosts);
1267 compute_neigh_stats.evaluate();
1268 }
1269}
1270
1271template<class Tvec, template<class> class Kern>
1273 // storage.neighbors_cache.reset();
1274}
1275
1276template<class Tvec, template<class> class Kern>
1278
1279 StackEntry stack_loc{};
1280
1281 shambase::Timer timer_interf;
1282 timer_interf.start();
1283
1284 using namespace shamrock;
1285 using namespace shamrock::patch;
1286
1287 bool has_alphaAV_field = solver_config.has_field_alphaAV();
1288 bool has_soundspeed_field = solver_config.ghost_has_soundspeed();
1289
1290 bool has_B_field = solver_config.has_field_B_on_rho();
1291 bool has_psi_field = solver_config.has_field_psi_on_ch();
1292 bool has_curlB_field = solver_config.has_field_curlB();
1293 bool has_epsilon_field = solver_config.dust_config.has_epsilon_field();
1294 bool has_deltav_field = solver_config.dust_config.has_deltav_field();
1295 bool has_s_j_field = solver_config.dust_config.has_s_j_field();
1296
1297 PatchDataLayerLayout &pdl = scheduler().pdl_old();
1298 const u32 ixyz = pdl.get_field_idx<Tvec>("xyz");
1299 const u32 ivxyz = pdl.get_field_idx<Tvec>("vxyz");
1300 const u32 iaxyz = pdl.get_field_idx<Tvec>("axyz");
1301 const u32 iuint = pdl.get_field_idx<Tscal>("uint");
1302 const u32 iduint = pdl.get_field_idx<Tscal>("duint");
1303 const u32 ihpart = pdl.get_field_idx<Tscal>("hpart");
1304
1305 const u32 ialpha_AV = (has_alphaAV_field) ? pdl.get_field_idx<Tscal>("alpha_AV") : 0;
1306 const u32 isoundspeed = (has_soundspeed_field) ? pdl.get_field_idx<Tscal>("soundspeed") : 0;
1307
1308 const u32 iB_on_rho = (has_B_field) ? pdl.get_field_idx<Tvec>("B/rho") : 0;
1309 const u32 idB_on_rho = (has_B_field) ? pdl.get_field_idx<Tvec>("dB/rho") : 0;
1310 const u32 ipsi_on_ch = (has_psi_field) ? pdl.get_field_idx<Tscal>("psi/ch") : 0;
1311 const u32 idpsi_on_ch = (has_psi_field) ? pdl.get_field_idx<Tscal>("dpsi/ch") : 0;
1312 const u32 icurlB = (has_curlB_field) ? pdl.get_field_idx<Tvec>("curlB") : 0;
1313
1314 bool do_MHD_debug = solver_config.do_MHD_debug();
1315 const u32 imag_pressure = (do_MHD_debug) ? pdl.get_field_idx<Tvec>("mag_pressure") : -1;
1316 const u32 imag_tension = (do_MHD_debug) ? pdl.get_field_idx<Tvec>("mag_tension") : -1;
1317 const u32 igas_pressure = (do_MHD_debug) ? pdl.get_field_idx<Tvec>("gas_pressure") : -1;
1318 const u32 itensile_corr = (do_MHD_debug) ? pdl.get_field_idx<Tvec>("tensile_corr") : -1;
1319 const u32 ipsi_propag = (do_MHD_debug) ? pdl.get_field_idx<Tscal>("psi_propag") : -1;
1320 const u32 ipsi_diff = (do_MHD_debug) ? pdl.get_field_idx<Tscal>("psi_diff") : -1;
1321 const u32 ipsi_cons = (do_MHD_debug) ? pdl.get_field_idx<Tscal>("psi_cons") : -1;
1322 const u32 iu_mhd = (do_MHD_debug) ? pdl.get_field_idx<Tscal>("u_mhd") : -1;
1323
1324 const u32 iepsilon = (has_epsilon_field) ? pdl.get_field_idx<Tscal>("epsilon") : 0;
1325 const u32 ideltav = (has_deltav_field) ? pdl.get_field_idx<Tvec>("deltav") : 0;
1326 const u32 is_j = (has_s_j_field) ? pdl.get_field_idx<Tscal>("s_j") : 0;
1327
1328 auto &ghost_layout_ptr = storage.ghost_layout;
1329 shamrock::patch::PatchDataLayerLayout &ghost_layout = shambase::get_check_ref(ghost_layout_ptr);
1330 u32 ihpart_interf = ghost_layout.get_field_idx<Tscal>("hpart");
1331 u32 iuint_interf = ghost_layout.get_field_idx<Tscal>("uint");
1332 u32 ivxyz_interf = ghost_layout.get_field_idx<Tvec>("vxyz");
1333 u32 iomega_interf = ghost_layout.get_field_idx<Tscal>("omega");
1334
1335 const u32 iaxyz_interf
1336 = (solver_config.has_axyz_in_ghost()) ? ghost_layout.get_field_idx<Tvec>("axyz") : 0;
1337
1338 const u32 isoundspeed_interf
1339 = (has_soundspeed_field) ? ghost_layout.get_field_idx<Tscal>("soundspeed") : 0;
1340
1341 const u32 iB_interf = (has_B_field) ? ghost_layout.get_field_idx<Tvec>("B/rho") : 0;
1342 const u32 ipsi_interf = (has_psi_field) ? ghost_layout.get_field_idx<Tscal>("psi/ch") : 0;
1343 const u32 icurlB_interf = (has_curlB_field) ? ghost_layout.get_field_idx<Tvec>("curlB") : 0;
1344
1345 const u32 iepsilon_interf
1346 = (has_epsilon_field) ? ghost_layout.get_field_idx<Tscal>("epsilon") : 0;
1347 const u32 ideltav_interf = (has_deltav_field) ? ghost_layout.get_field_idx<Tvec>("deltav") : 0;
1348 const u32 is_j_interf = (has_s_j_field) ? ghost_layout.get_field_idx<Tscal>("s_j") : 0;
1349
1350 using InterfaceBuildInfos = typename sph::BasicSPHGhostHandler<Tvec>::InterfaceBuildInfos;
1351
1352 sph::BasicSPHGhostHandler<Tvec> &ghost_handle = storage.ghost_handler.get();
1354
1355 auto pdat_interf = ghost_handle.template build_interface_native<PatchDataLayer>(
1356 storage.ghost_patch_cache.get(),
1357 [&](u64 sender, u64, InterfaceBuildInfos binfo, sham::DeviceBuffer<u32> &buf_idx, u32 cnt) {
1358 PatchDataLayer pdat(ghost_layout_ptr);
1359
1360 pdat.reserve(cnt);
1361
1362 return pdat;
1363 });
1364
1365 ghost_handle.template modify_interface_native<PatchDataLayer>(
1366 storage.ghost_patch_cache.get(),
1367 pdat_interf,
1368 [&](u64 sender,
1369 u64,
1370 InterfaceBuildInfos binfo,
1371 sham::DeviceBuffer<u32> &buf_idx,
1372 u32 cnt,
1373 PatchDataLayer &pdat) {
1374 PatchDataLayer &sender_patch = scheduler().patch_data.get_pdat(sender);
1375 PatchDataField<Tscal> &sender_omega = omega.get(sender);
1376
1377 sender_patch.get_field<Tscal>(ihpart).append_subset_to(
1378 buf_idx, cnt, pdat.get_field<Tscal>(ihpart_interf));
1379 sender_patch.get_field<Tscal>(iuint).append_subset_to(
1380 buf_idx, cnt, pdat.get_field<Tscal>(iuint_interf));
1381
1382 if (solver_config.has_axyz_in_ghost()) {
1383 sender_patch.get_field<Tvec>(iaxyz).append_subset_to(
1384 buf_idx, cnt, pdat.get_field<Tvec>(iaxyz_interf));
1385 }
1386
1387 sender_patch.get_field<Tvec>(ivxyz).append_subset_to(
1388 buf_idx, cnt, pdat.get_field<Tvec>(ivxyz_interf));
1389
1390 sender_omega.append_subset_to(buf_idx, cnt, pdat.get_field<Tscal>(iomega_interf));
1391
1392 if (has_soundspeed_field) {
1393 sender_patch.get_field<Tscal>(isoundspeed)
1394 .append_subset_to(buf_idx, cnt, pdat.get_field<Tscal>(isoundspeed_interf));
1395 }
1396
1397 if (has_B_field) {
1398 sender_patch.get_field<Tvec>(iB_on_rho).append_subset_to(
1399 buf_idx, cnt, pdat.get_field<Tvec>(iB_interf));
1400 }
1401
1402 if (has_psi_field) {
1403 sender_patch.get_field<Tscal>(ipsi_on_ch)
1404 .append_subset_to(buf_idx, cnt, pdat.get_field<Tscal>(ipsi_interf));
1405 }
1406
1407 if (has_curlB_field) {
1408 sender_patch.get_field<Tvec>(icurlB).append_subset_to(
1409 buf_idx, cnt, pdat.get_field<Tvec>(icurlB_interf));
1410 }
1411
1412 if (has_epsilon_field) {
1413 sender_patch.get_field<Tscal>(iepsilon).append_subset_to(
1414 buf_idx, cnt, pdat.get_field<Tscal>(iepsilon_interf));
1415 }
1416
1417 if (has_deltav_field) {
1418 sender_patch.get_field<Tvec>(ideltav).append_subset_to(
1419 buf_idx, cnt, pdat.get_field<Tvec>(ideltav_interf));
1420 }
1421
1422 if (has_s_j_field) {
1423 sender_patch.get_field<Tscal>(is_j).append_subset_to(
1424 buf_idx, cnt, pdat.get_field<Tscal>(is_j_interf));
1425 }
1426 });
1427
1428 ghost_handle.template modify_interface_native<PatchDataLayer>(
1429 storage.ghost_patch_cache.get(),
1430 pdat_interf,
1431 [&](u64 sender,
1432 u64,
1433 InterfaceBuildInfos binfo,
1434 sham::DeviceBuffer<u32> &buf_idx,
1435 u32 cnt,
1436 PatchDataLayer &pdat) {
1437 if (sycl::length(binfo.offset_speed) > 0) {
1438 pdat.get_field<Tvec>(ivxyz_interf).apply_offset(binfo.offset_speed);
1439 }
1440 });
1441
1442 shambase::DistributedDataShared<PatchDataLayer> interf_pdat = ghost_handle.communicate_pdat(
1443 ghost_layout_ptr,
1444 std::move(pdat_interf),
1445 storage.exchange_gz_node,
1446 solver_config.show_ghost_zone_graph);
1447
1448 std::map<u64, u64> sz_interf_map;
1449 interf_pdat.for_each([&](u64 s, u64 r, PatchDataLayer &pdat_interf) {
1450 sz_interf_map[r] += pdat_interf.get_obj_cnt();
1451 });
1452
1453 storage.merged_patchdata_ghost.set(
1454 ghost_handle.template merge_native<PatchDataLayer, PatchDataLayer>(
1455 std::move(interf_pdat),
1457 PatchDataLayer pdat_new(ghost_layout_ptr);
1458
1459 u32 or_elem = pdat.get_obj_cnt();
1460 pdat_new.reserve(or_elem + sz_interf_map[p.id_patch]);
1461 u32 total_elements = or_elem;
1462
1463 PatchDataField<Tscal> &cur_omega = omega.get(p.id_patch);
1464
1465 pdat_new.get_field<Tscal>(ihpart_interf).insert(pdat.get_field<Tscal>(ihpart));
1466 pdat_new.get_field<Tscal>(iuint_interf).insert(pdat.get_field<Tscal>(iuint));
1467 pdat_new.get_field<Tvec>(ivxyz_interf).insert(pdat.get_field<Tvec>(ivxyz));
1468
1469 if (solver_config.has_axyz_in_ghost()) {
1470 pdat_new.get_field<Tvec>(iaxyz_interf).insert(pdat.get_field<Tvec>(iaxyz));
1471 }
1472
1473 pdat_new.get_field<Tscal>(iomega_interf).insert(cur_omega);
1474
1475 if (has_soundspeed_field) {
1476 pdat_new.get_field<Tscal>(isoundspeed_interf)
1477 .insert(pdat.get_field<Tscal>(isoundspeed));
1478 }
1479
1480 if (has_B_field) {
1481 pdat_new.get_field<Tvec>(iB_interf).insert(pdat.get_field<Tvec>(iB_on_rho));
1482 }
1483
1484 if (has_psi_field) {
1485 pdat_new.get_field<Tscal>(ipsi_interf)
1486 .insert(pdat.get_field<Tscal>(ipsi_on_ch));
1487 }
1488
1489 if (has_curlB_field) {
1490 pdat_new.get_field<Tvec>(icurlB_interf).insert(pdat.get_field<Tvec>(icurlB));
1491 }
1492
1493 if (has_epsilon_field) {
1494 pdat_new.get_field<Tscal>(iepsilon_interf)
1495 .insert(pdat.get_field<Tscal>(iepsilon));
1496 }
1497
1498 if (has_deltav_field) {
1499 pdat_new.get_field<Tvec>(ideltav_interf).insert(pdat.get_field<Tvec>(ideltav));
1500 }
1501
1502 if (has_s_j_field) {
1503 pdat_new.get_field<Tscal>(is_j_interf).insert(pdat.get_field<Tscal>(is_j));
1504 }
1505
1506 pdat_new.check_field_obj_cnt_match();
1507
1508 return pdat_new;
1509 },
1510 [](PatchDataLayer &pdat, PatchDataLayer &pdat_interf) {
1511 pdat.insert_elements(pdat_interf);
1512 }));
1513
1514 timer_interf.stop();
1515 storage.timings_details.interface += timer_interf.elapsed_sec();
1516}
1517
1518template<class Tvec, template<class> class Kern>
1520 storage.merged_patchdata_ghost.reset();
1521}
1522
1524// start artificial viscosity section //////////////////////////////////////////////////////////////
1526
1527template<class Tvec, template<class> class Kern>
1529
1530 sph::modules::UpdateViscosity<Tvec, Kern>(context, solver_config, storage)
1531 .update_artificial_viscosity(dt);
1532}
1533
1535// end artificial viscosity section ////////////////////////////////////////////////////////////////
1537
1538template<class Tvec, template<class> class Kern>
1543
1544template<class Tvec, template<class> class Kern>
1546 shambase::get_check_ref(storage.pressure).free_alloc();
1547 shambase::get_check_ref(storage.soundspeed).free_alloc();
1548}
1549
1550template<class Tvec, template<class> class Kern>
1552
1553 StackEntry stack_loc{};
1554
1555 using namespace shamrock;
1556 using namespace shamrock::patch;
1557 shamrock::SchedulerUtility utility(scheduler());
1558 PatchDataLayerLayout &pdl = scheduler().pdl_old();
1559
1560 bool has_B_field = solver_config.has_field_B_on_rho();
1561 bool has_psi_field = solver_config.has_field_psi_on_ch();
1562 bool has_epsilon_field = solver_config.dust_config.has_epsilon_field();
1563 bool has_deltav_field = solver_config.dust_config.has_deltav_field();
1564 bool has_s_j_field = solver_config.dust_config.has_s_j_field();
1565
1566 const u32 iduint = pdl.get_field_idx<Tscal>("duint");
1567 const u32 iaxyz = pdl.get_field_idx<Tvec>("axyz");
1568 const u32 idB_on_rho = (has_B_field) ? pdl.get_field_idx<Tvec>("dB/rho") : 0;
1569 const u32 idpsi_on_ch = (has_psi_field) ? pdl.get_field_idx<Tscal>("dpsi/ch") : 0;
1570
1571 shamlog_debug_ln("sph::BasicGas", "save old fields");
1572 storage.old_axyz.set(utility.save_field<Tvec>(iaxyz, "axyz_old"));
1573 storage.old_duint.set(utility.save_field<Tscal>(iduint, "duint_old"));
1574
1575 if (has_B_field) {
1576 storage.old_dB_on_rho.set(utility.save_field<Tvec>(idB_on_rho, "dB/rho_old"));
1577 }
1578 if (has_psi_field) {
1579 storage.old_dpsi_on_ch.set(utility.save_field<Tscal>(idpsi_on_ch, "dpsi/ch_old"));
1580 }
1581 if (has_epsilon_field) {
1582 storage.old_dtepsilon.set(
1583 utility.save_field<Tscal>(pdl.get_field_idx<Tscal>("dtepsilon"), "dtepsilon_old"));
1584 }
1585 if (has_deltav_field) {
1586 storage.old_dtdeltav.set(
1587 utility.save_field<Tvec>(pdl.get_field_idx<Tvec>("dtdeltav"), "dtdeltav_old"));
1588 }
1589 if (has_s_j_field) {
1590 storage.old_ds_j_dt.set(
1591 utility.save_field<Tscal>(pdl.get_field_idx<Tscal>("ds_j_dt"), "ds_j_dt_old"));
1592 }
1593}
1594
1595template<class T>
1596void map_field_refs(
1597 PatchScheduler &sched, u32 field_idx, shamrock::solvergraph::FieldRefs<T> &refs) {
1598
1599 using namespace shamrock::solvergraph;
1600 using namespace shamrock::patch;
1601
1603 sched.for_each_patchdata_nonempty([&](const Patch p, PatchDataLayer &pdat) {
1604 auto &field = pdat.get_field<T>(field_idx);
1605 field_refs.add_obj(p.id_patch, std::ref(field));
1606 });
1607 refs.set_refs(field_refs);
1608}
1609
1610template<class T>
1611void map_field_refs_ext(
1612 PatchScheduler &sched,
1614 u32 field_idx,
1616
1617 using namespace shamrock::solvergraph;
1618 using namespace shamrock::patch;
1619
1621 sched.for_each_patchdata_nonempty([&](const Patch p, PatchDataLayer &pdat) {
1622 PatchDataLayer &mpdat = mpdats.get(p.id_patch);
1623 auto &field = mpdat.get_field<T>(field_idx);
1624 field_refs.add_obj(p.id_patch, std::ref(field));
1625 });
1626 refs.set_refs(field_refs);
1627}
1628
1629template<class T>
1630void map_field_refs_ext(
1631 PatchScheduler &sched,
1632 shamrock::ComputeField<T> &field_data,
1634
1635 using namespace shamrock::solvergraph;
1636 using namespace shamrock::patch;
1637
1639 sched.for_each_patchdata_nonempty([&](const Patch p, PatchDataLayer &pdat) {
1640 auto &field = field_data.get_field(p.id_patch);
1641 field_refs.add_obj(p.id_patch, std::ref(field));
1642 });
1643 refs.set_refs(field_refs);
1644}
1645
1646template<class Tvec, template<class> class Kern>
1648
1649 // if one fluid is enabled time to compute the stopping times
1650 if (solver_config.dust_config.has_s_j_field()) {
1651
1652 auto &cfg = solver_config.dust_config;
1653 u32 ndust = cfg.get_dust_nvar();
1654
1655 using DustConfig = typename Config::DustConfig;
1656
1657 using None = typename DustConfig::None;
1658 using ConstantStoppingTimes = typename DustConfig::ConstantStoppingTimes;
1659 using EpsteinDrag = typename DustConfig::EpsteinDrag;
1660
1662 = shambase::get_check_ref(storage.ghost_layout.get());
1663 shamrock::patch::PatchDataLayerLayout &pdl = scheduler().pdl_old();
1664
1665 u32 ihpart_interf = ghost_layout.get_field_idx<Tscal>("hpart");
1666
1667 auto &part_counts_with_ghost = storage.part_counts_with_ghost;
1668 auto &part_counts = storage.part_counts;
1669
1671 = storage.merged_patchdata_ghost.get();
1672
1673 std::shared_ptr<shamrock::solvergraph::FieldRefs<Tscal>> hpart_refs
1674 = std::make_shared<shamrock::solvergraph::FieldRefs<Tscal>>("hpart", "h");
1675 { // if was just reset before this call
1676 shambase::get_check_ref(hpart_refs)
1677 .set_refs(mpdats.map<std::reference_wrapper<PatchDataField<Tscal>>>(
1678 [&](u64 id, shamrock::patch::PatchDataLayer &mpdat) {
1679 return std::ref(mpdat.get_field<Tscal>(ihpart_interf));
1680 }));
1681 }
1682
1683 auto gpart_mass
1684 = storage.solver_graph.template get_edge_ptr<shamrock::solvergraph::ScalarEdge<Tscal>>(
1685 "gpart_mass");
1686 auto t_j_field
1687 = storage.solver_graph.template get_edge_ptr<shamrock::solvergraph::Field<Tscal>>(
1688 "Ts_j");
1689
1690 if (std::holds_alternative<None>(cfg.dust_drag_mode)) {
1691
1692 throw "bro WTF";
1693
1694 } else if (
1695 ConstantStoppingTimes *cfg_drag
1696 = std::get_if<ConstantStoppingTimes>(&cfg.dust_drag_mode)) {
1697
1698 std::shared_ptr<shamrock::solvergraph::ScalarEdge<std::vector<Tscal>>> input_t_j
1699 = std::make_shared<shamrock::solvergraph::ScalarEdge<std::vector<Tscal>>>("", "");
1700 input_t_j->value = cfg_drag->stopping_times;
1701
1702 std::shared_ptr<modules::SetDustStoppingTimeConstant<Tvec>> node_set_tj
1703 = std::make_shared<modules::SetDustStoppingTimeConstant<Tvec>>(ndust);
1704 {
1705 node_set_tj->set_edges(input_t_j, part_counts_with_ghost, t_j_field);
1706 }
1707 node_set_tj->evaluate();
1708
1709 } else if (EpsteinDrag *cfg_drag = std::get_if<EpsteinDrag>(&cfg.dust_drag_mode)) {
1710
1711 std::shared_ptr<shamrock::solvergraph::ScalarEdge<Tscal>> input_gamma
1712 = std::make_shared<shamrock::solvergraph::ScalarEdge<Tscal>>("", "");
1713 input_gamma->value = cfg_drag->gamma;
1714
1715 std::shared_ptr<shamrock::solvergraph::ScalarEdge<std::vector<Tscal>>> input_sgrain_j
1716 = std::make_shared<shamrock::solvergraph::ScalarEdge<std::vector<Tscal>>>("", "");
1717 input_sgrain_j->value = cfg_drag->grains_sizes;
1718
1719 std::shared_ptr<shamrock::solvergraph::ScalarEdge<std::vector<Tscal>>> input_rho_grain_j
1720 = std::make_shared<shamrock::solvergraph::ScalarEdge<std::vector<Tscal>>>("", "");
1721 input_rho_grain_j->value = cfg_drag->grains_densities;
1722
1723 std::shared_ptr<modules::SetDustStoppingTimeEpstein<Tvec, Kern>> node_set_tj
1724 = std::make_shared<modules::SetDustStoppingTimeEpstein<Tvec, Kern>>(ndust);
1725 {
1726 node_set_tj->set_edges(
1727 gpart_mass,
1728 input_gamma,
1729 input_sgrain_j,
1730 input_rho_grain_j,
1731 part_counts_with_ghost,
1732 hpart_refs,
1733 storage.soundspeed,
1734 t_j_field);
1735 }
1736 node_set_tj->evaluate();
1737 }
1738
1739 if (cfg.ballabio_ts_limiter) {
1740 std::shared_ptr<modules::BallabioTsLimiter<Tvec>> node_ballabio_ts_limiter
1741 = std::make_shared<modules::BallabioTsLimiter<Tvec>>(ndust);
1742 {
1743 node_ballabio_ts_limiter->set_edges(
1744 part_counts_with_ghost, hpart_refs, storage.soundspeed, t_j_field);
1745 }
1746 node_ballabio_ts_limiter->evaluate();
1747 }
1748
1749 // delta v computation (for CFL or other uses e.g. COALA)
1750 auto &pressure_field = storage.pressure;
1751 auto &xyz_refs = storage.positions_with_ghosts;
1752
1753 std::shared_ptr<shamrock::solvergraph::FieldRefs<Tscal>> omega_refs
1754 = std::make_shared<shamrock::solvergraph::FieldRefs<Tscal>>("omega", "omega");
1755 {
1756 u32 iomega_interf = ghost_layout.get_field_idx<Tscal>("omega");
1757 shambase::get_check_ref(omega_refs)
1758 .set_refs(mpdats.map<std::reference_wrapper<PatchDataField<Tscal>>>(
1759 [iomega_interf](u64 id, shamrock::patch::PatchDataLayer &mpdat) {
1760 return std::ref(mpdat.get_field<Tscal>(iomega_interf));
1761 }));
1762 }
1763
1764 std::shared_ptr<shamrock::solvergraph::FieldRefs<Tscal>> s_j_refs
1765 = std::make_shared<shamrock::solvergraph::FieldRefs<Tscal>>("s_j", "s_j");
1766 {
1767 u32 is_j_interf = ghost_layout.get_field_idx<Tscal>("s_j");
1768 shambase::get_check_ref(s_j_refs).set_refs(
1769 mpdats.map<std::reference_wrapper<PatchDataField<Tscal>>>(
1770 [is_j_interf](u64 id, shamrock::patch::PatchDataLayer &mpdat) {
1771 return std::ref(mpdat.get_field<Tscal>(is_j_interf));
1772 }));
1773 }
1774
1775 std::shared_ptr<shamrock::solvergraph::Field<Tvec>> grad_P_on_rho
1776 = std::make_shared<shamrock::solvergraph::Field<Tvec>>(1, "grad P/rho", "grad P/rho");
1777
1778 u32 idelta_v = pdl.get_field_idx<Tvec>("delta_v");
1779
1780 std::shared_ptr<shamrock::solvergraph::FieldRefs<Tvec>> delta_v
1781 = std::make_shared<shamrock::solvergraph::FieldRefs<Tvec>>("Delta v", "Delta v");
1782 map_field_refs(scheduler(), idelta_v, *delta_v);
1783
1784 auto press_grad_node = std::make_shared<modules::NodeComputePressureGrad<Tvec, Kern>>();
1785 auto delta_v_node = std::make_shared<modules::MonoFluidTVADeltav<Tvec, Kern>>(ndust);
1786
1787 press_grad_node->set_edges(
1788 gpart_mass,
1789 part_counts,
1790 part_counts_with_ghost,
1791 xyz_refs,
1792 hpart_refs,
1793 omega_refs,
1794 pressure_field,
1795 storage.neigh_cache,
1796 grad_P_on_rho);
1797
1798 delta_v_node->set_edges(
1799 gpart_mass, part_counts, hpart_refs, grad_P_on_rho, s_j_refs, t_j_field, delta_v);
1800
1801 press_grad_node->evaluate();
1802 delta_v_node->evaluate();
1803 }
1804
1805 modules::UpdateDerivs<Tvec, Kern> derivs(context, solver_config, storage);
1806 derivs.update_derivs(dt_hydro);
1807
1808 modules::ExternalForces<Tvec, Kern> ext_forces(context, solver_config, storage);
1809 ext_forces.add_ext_forces();
1810}
1811
1812template<class Tvec, template<class> class Kern>
1814 return false;
1815}
1816
1817template<class Tvec, template<class> class Kern>
1819 modules::ComputeLoadBalanceValue<Tvec, Kern>(context, solver_config, storage)
1820 .update_load_balancing();
1821 scheduler().scheduler_step(false, false);
1822}
1823
1824template<class Tvec, template<class> class Kern>
1826
1827 // has to be first since there is a barrier that may mess the other timers
1828 shamsys::SystemMetrics system_metrics_start = shamsys::get_system_metrics();
1829
1831 f64 mpi_timer_start = shamcomm::mpi::get_timer("total");
1832
1833 for (auto &callbacks : timestep_callbacks) {
1834 if (callbacks.step_begin_callback) {
1835 shambase::get_check_ref(callbacks.step_begin_callback)();
1836 }
1837 }
1838
1839 Tscal t_current = get_time();
1840 Tscal dt = get_dt_sph();
1841
1842 StackEntry stack_loc{};
1843
1844 if (shamcomm::world_rank() == 0) {
1846 shambase::format("---------------- t = {}, dt = {} ----------------", t_current, dt));
1847 }
1848
1849 shambase::Timer tstep;
1850 tstep.start();
1851
1852 // if(shamcomm::world_rank() == 0) std::cout << scheduler().dump_status() << std::endl;
1853 modules::ComputeLoadBalanceValue<Tvec, Kern>(context, solver_config, storage)
1854 .update_load_balancing();
1855 scheduler().scheduler_step(true, true);
1856 modules::ComputeLoadBalanceValue<Tvec, Kern>(context, solver_config, storage)
1857 .update_load_balancing();
1858 // if(shamcomm::world_rank() == 0) std::cout << scheduler().dump_status() << std::endl;
1859 scheduler().scheduler_step(false, false);
1860 // if(shamcomm::world_rank() == 0) std::cout << scheduler().dump_status() << std::endl;
1861
1863
1864 using namespace shamrock;
1865 using namespace shamrock::patch;
1866
1867 bool has_B_field = solver_config.has_field_B_on_rho();
1868 bool has_psi_field = solver_config.has_field_psi_on_ch();
1869 bool has_epsilon_field = solver_config.dust_config.has_epsilon_field();
1870 bool has_deltav_field = solver_config.dust_config.has_deltav_field();
1871 bool has_s_j_field = solver_config.dust_config.has_s_j_field();
1872
1873 PatchDataLayerLayout &pdl = scheduler().pdl_old();
1874
1875 const u32 ixyz = pdl.get_field_idx<Tvec>("xyz");
1876 const u32 ivxyz = pdl.get_field_idx<Tvec>("vxyz");
1877 const u32 iaxyz = pdl.get_field_idx<Tvec>("axyz");
1878 const u32 iuint = pdl.get_field_idx<Tscal>("uint");
1879 const u32 iduint = pdl.get_field_idx<Tscal>("duint");
1880 const u32 ihpart = pdl.get_field_idx<Tscal>("hpart");
1881 const u32 iB_on_rho = (has_B_field) ? pdl.get_field_idx<Tvec>("B/rho") : 0;
1882 const u32 idB_on_rho = (has_B_field) ? pdl.get_field_idx<Tvec>("dB/rho") : 0;
1883 const u32 ipsi_on_ch = (has_psi_field) ? pdl.get_field_idx<Tscal>("psi/ch") : 0;
1884 const u32 idpsi_on_ch = (has_psi_field) ? pdl.get_field_idx<Tscal>("dpsi/ch") : 0;
1885 const u32 iepsilon = (has_epsilon_field) ? pdl.get_field_idx<Tscal>("epsilon") : 0;
1886 const u32 idtepsilon = (has_epsilon_field) ? pdl.get_field_idx<Tscal>("dtepsilon") : 0;
1887 const u32 is_j = (has_s_j_field) ? pdl.get_field_idx<Tscal>("s_j") : 0;
1888 const u32 ids_j_dt = (has_s_j_field) ? pdl.get_field_idx<Tscal>("ds_j_dt") : 0;
1889 const u32 ideltav = (has_deltav_field) ? pdl.get_field_idx<Tvec>("deltav") : 0;
1890 const u32 idtdeltav = (has_deltav_field) ? pdl.get_field_idx<Tvec>("dtdeltav") : 0;
1891
1892 shamrock::SchedulerUtility utility(scheduler());
1893
1894 modules::SinkParticlesUpdate<Tvec, Kern> sink_update(context, solver_config, storage);
1895 modules::ExternalForces<Tvec, Kern> ext_forces(context, solver_config, storage);
1896
1897 sink_update.accrete_particles(dt);
1898 ext_forces.point_mass_accrete_particles();
1899
1900 sink_update.predictor_step(dt);
1901
1902 {
1903 // beginning of SolverGraph migration
1904
1905 using namespace shamrock::solvergraph;
1906
1907 SolverGraph &solver_graph = storage.solver_graph;
1908
1910 // Solver evaluation
1912
1913 shambase::get_check_ref(storage.solver_sequence).evaluate();
1914 }
1915
1916 sink_update.compute_ext_forces();
1917
1918 ext_forces.compute_ext_forces_indep_v();
1919
1920 gen_serial_patch_tree();
1921
1922 apply_position_boundary(t_current + dt);
1923
1924 u64 Npart_all = scheduler().get_total_obj_count();
1925
1926 if (solver_config.enable_particle_reordering
1927 && solve_logs.step_count % solver_config.particle_reordering_step_freq == 0) {
1928 logger::info_ln("SPH", "Reordering particles at step ", solve_logs.step_count);
1929 modules::ParticleReordering<Tvec, u_morton, Kern>(context, solver_config, storage)
1931 }
1932
1933 {
1934 // update part counts and spans since particles have been moved and thus
1935 // new patch can be non-empty/empty
1936 using namespace shamrock::solvergraph;
1937 SolverGraph &solver_graph = storage.solver_graph;
1938 solver_graph.get_node_ref_base("attach fields to scheduler").evaluate();
1939 }
1940
1941 sph_prestep(t_current, dt);
1942
1944
1945 // Here we will add self grav to the external forces indep of vel (this will be moved into a
1946 // sperate module later)
1947 if (solver_config.self_grav_config.is_sg_on()) {
1948
1949 auto constant_G = shamrock::solvergraph::IDataEdge<Tscal>::make_shared("", "");
1950
1953 constant_G.data = solver_config.get_constant_G();
1954 });
1955
1956 set_constant_G.set_edges(constant_G);
1957
1958 auto field_xyz = shamrock::solvergraph::FieldRefs<Tvec>::make_shared("", "");
1959
1961 [&](shamrock::solvergraph::FieldRefs<Tvec> &field_xyz_edge) {
1963 scheduler().for_each_patchdata_nonempty([&](const Patch p, PatchDataLayer &pdat) {
1964 auto &field = pdat.get_field<Tvec>(ixyz);
1965 field_xyz_refs.add_obj(p.id_patch, std::ref(field));
1966 });
1967 field_xyz_edge.set_refs(field_xyz_refs);
1968 });
1969 set_field_xyz.set_edges(field_xyz);
1970
1971 const u32 iaxyz_ext = pdl.get_field_idx<Tvec>("axyz_ext");
1972
1973 auto field_axyz_ext = shamrock::solvergraph::FieldRefs<Tvec>::make_shared("", "");
1974
1976 set_field_axyz_ext([&](shamrock::solvergraph::FieldRefs<Tvec> &field_axyz_ext_edge) {
1977 shamrock::solvergraph::DDPatchDataFieldRef<Tvec> field_axyz_ext_refs = {};
1978 scheduler().for_each_patchdata_nonempty([&](const Patch p, PatchDataLayer &pdat) {
1979 auto &field = pdat.get_field<Tvec>(iaxyz_ext);
1980 field_axyz_ext_refs.add_obj(p.id_patch, std::ref(field));
1981 });
1982 field_axyz_ext_edge.set_refs(field_axyz_ext_refs);
1983 });
1984 set_field_axyz_ext.set_edges(field_axyz_ext);
1985
1986 auto sizes = shamrock::solvergraph::Indexes<u32>::make_shared("", "");
1987
1990 sizes.indexes = {};
1991 scheduler().for_each_patchdata_nonempty([&](const Patch p, PatchDataLayer &pdat) {
1992 sizes.indexes.add_obj(p.id_patch, pdat.get_obj_cnt());
1993 });
1994 });
1995 set_sizes.set_edges(sizes);
1996
1997 auto gpart_mass = shamrock::solvergraph::IDataEdge<Tscal>::make_shared("", "");
1998
2001 gpart_mass.data = solver_config.gpart_mass;
2002 });
2003
2004 set_gpart_mass.set_edges(gpart_mass);
2005
2006 set_gpart_mass.evaluate();
2007 set_constant_G.evaluate();
2008 set_field_xyz.evaluate();
2009 set_field_axyz_ext.evaluate();
2010 set_sizes.evaluate();
2011
2012 Tscal eps_grav = shambase::get_check_ref(
2013 std::get_if<SelfGravConfig::SofteningPlummer>(
2014 &solver_config.self_grav_config.softening_mode))
2015 .epsilon;
2016
2017 if (solver_config.self_grav_config.is_none()) {
2018 // do nothing
2019 } else if (solver_config.self_grav_config.is_direct()) {
2020
2022 std::get_if<SelfGravConfig::Direct>(&solver_config.self_grav_config.config));
2023
2024 modules::SGDirectPlummer<Tvec> self_gravity_direct_node(
2025 eps_grav, direct_config.reference_mode);
2026 self_gravity_direct_node.set_edges(
2027 sizes, gpart_mass, constant_G, field_xyz, field_axyz_ext);
2028 self_gravity_direct_node.evaluate();
2029
2030 } else if (solver_config.self_grav_config.is_mm()) {
2031
2033 std::get_if<SelfGravConfig::MM>(&solver_config.self_grav_config.config));
2034
2035 auto run_sg_mm = [&](auto mm_order_tag) {
2036 constexpr u32 order = decltype(mm_order_tag)::value;
2037 modules::SGMMPlummer<Tvec, order> self_gravity_mm_node(
2038 eps_grav, mm_config.opening_angle, mm_config.reduction_level);
2039 self_gravity_mm_node.set_edges(
2040 sizes, gpart_mass, constant_G, field_xyz, field_axyz_ext);
2041 self_gravity_mm_node.evaluate();
2042 };
2043
2044 switch (mm_config.order) {
2045 case 1 : run_sg_mm(std::integral_constant<u32, 1>{}); break;
2046 case 2 : run_sg_mm(std::integral_constant<u32, 2>{}); break;
2047 case 3 : run_sg_mm(std::integral_constant<u32, 3>{}); break;
2048 case 4 : run_sg_mm(std::integral_constant<u32, 4>{}); break;
2049 case 5 : run_sg_mm(std::integral_constant<u32, 5>{}); break;
2051 }
2052
2053 } else if (solver_config.self_grav_config.is_fmm()) {
2054
2056 std::get_if<SelfGravConfig::FMM>(&solver_config.self_grav_config.config));
2057
2058 auto run_sg_fmm = [&](auto fmm_order_tag) {
2059 constexpr u32 order = decltype(fmm_order_tag)::value;
2060 modules::SGFMMPlummer<Tvec, order> self_gravity_mm_node(
2061 eps_grav, fmm_config.opening_angle, fmm_config.reduction_level);
2062 self_gravity_mm_node.set_edges(
2063 sizes, gpart_mass, constant_G, field_xyz, field_axyz_ext);
2064 self_gravity_mm_node.evaluate();
2065 };
2066
2067 switch (fmm_config.order) {
2068 case 1 : run_sg_fmm(std::integral_constant<u32, 1>{}); break;
2069 case 2 : run_sg_fmm(std::integral_constant<u32, 2>{}); break;
2070 case 3 : run_sg_fmm(std::integral_constant<u32, 3>{}); break;
2071 case 4 : run_sg_fmm(std::integral_constant<u32, 4>{}); break;
2072 case 5 : run_sg_fmm(std::integral_constant<u32, 5>{}); break;
2074 }
2075
2076 } else if (solver_config.self_grav_config.is_sfmm()) {
2077
2079 std::get_if<SelfGravConfig::SFMM>(&solver_config.self_grav_config.config));
2080
2081 auto run_sg_sfmm = [&](auto sfmm_order_tag) {
2082 constexpr u32 order = decltype(sfmm_order_tag)::value;
2083 modules::SGSFMMPlummer<Tvec, order> self_gravity_mm_node(
2084 eps_grav,
2085 sfmm_config.opening_angle,
2086 sfmm_config.leaf_lowering,
2087 sfmm_config.reduction_level);
2088 self_gravity_mm_node.set_edges(
2089 sizes, gpart_mass, constant_G, field_xyz, field_axyz_ext);
2090 self_gravity_mm_node.evaluate();
2091 };
2092
2093 switch (sfmm_config.order) {
2094 case 1 : run_sg_sfmm(std::integral_constant<u32, 1>{}); break;
2095 case 2 : run_sg_sfmm(std::integral_constant<u32, 2>{}); break;
2096 case 3 : run_sg_sfmm(std::integral_constant<u32, 3>{}); break;
2097 case 4 : run_sg_sfmm(std::integral_constant<u32, 4>{}); break;
2098 case 5 : run_sg_sfmm(std::integral_constant<u32, 5>{}); break;
2100 }
2101
2102 } else {
2104 "Self gravity config not supported, current state is : \n"
2105 + nlohmann::json{solver_config.self_grav_config}.dump(4));
2106 }
2107 }
2108
2109 sph::BasicSPHGhostHandler<Tvec> &ghost_handle = storage.ghost_handler.get();
2110 auto &merged_xyzh = storage.merged_xyzh.get();
2111 shambase::DistributedData<RTree> &trees = storage.merged_pos_trees.get();
2112 // ComputeField<Tscal> &omega = storage.omega.get();
2113
2115 = shambase::get_check_ref(storage.ghost_layout.get());
2116 u32 ihpart_interf = ghost_layout.get_field_idx<Tscal>("hpart");
2117 u32 iuint_interf = ghost_layout.get_field_idx<Tscal>("uint");
2118 u32 ivxyz_interf = ghost_layout.get_field_idx<Tvec>("vxyz");
2119 u32 iomega_interf = ghost_layout.get_field_idx<Tscal>("omega");
2120 u32 iB_on_rho_interf = (has_B_field) ? ghost_layout.get_field_idx<Tvec>("B/rho") : 0;
2121 u32 ipsi_on_rho_interf = (has_psi_field) ? ghost_layout.get_field_idx<Tscal>("psi/ch") : 0;
2122
2123 using RTreeField = RadixTreeField<Tscal>;
2125
2126 Tscal next_cfl = 0;
2127
2128 u32 corrector_iter_cnt = 0;
2129 bool need_rerun_corrector = false;
2130 do {
2131
2134
2135 if (corrector_iter_cnt == 50) {
2137 "the corrector has made over 50 loops, either their is a bug, either you are using "
2138 "a dt that is too large");
2139 }
2140
2141 // communicate fields
2143
2144 if (solver_config.has_field_alphaAV()) {
2145
2146 std::shared_ptr<shamrock::solvergraph::PatchDataLayerRefs> patchdatas
2147 = std::make_shared<shamrock::solvergraph::PatchDataLayerRefs>(
2148 "patchdata_layer_ref", "patchdata_layer_ref");
2149
2150 auto node_set_edge = scheduler().get_node_set_edge_patchdata_layer_refs();
2151 node_set_edge->set_edges(patchdatas);
2152 node_set_edge->evaluate();
2153
2155 scheduler().get_layout_ptr_old(), "alpha_AV");
2156 node_copy.set_edges(patchdatas, storage.alpha_av_updated);
2157 node_copy.evaluate();
2158 }
2159
2160 if (solver_config.has_field_dtdivv()) {
2161
2162 if (solver_config.combined_dtdiv_divcurlv_compute) {
2163 if (solver_config.has_field_dtdivv()) {
2164 sph::modules::DiffOperatorDtDivv<Tvec, Kern>(context, solver_config, storage)
2165 .update_dtdivv(true);
2166 }
2167 } else {
2168
2169 if (solver_config.has_field_divv()) {
2170 sph::modules::DiffOperators<Tvec, Kern>(context, solver_config, storage)
2171 .update_divv();
2172 }
2173
2174 if (solver_config.has_field_curlv()) {
2175 sph::modules::DiffOperators<Tvec, Kern>(context, solver_config, storage)
2176 .update_curlv();
2177 }
2178
2179 if (solver_config.has_field_dtdivv()) {
2180 sph::modules::DiffOperatorDtDivv<Tvec, Kern>(context, solver_config, storage)
2181 .update_dtdivv(false);
2182 }
2183 }
2184
2185 } else {
2186 if (solver_config.has_field_divv()) {
2187 sph::modules::DiffOperators<Tvec, Kern>(context, solver_config, storage)
2188 .update_divv();
2189 }
2190
2191 if (solver_config.has_field_curlv()) {
2192 sph::modules::DiffOperators<Tvec, Kern>(context, solver_config, storage)
2193 .update_curlv();
2194 }
2195 }
2196
2197 // if (solver_config.has_field_divB()) {
2198 // sph::modules::DiffOperatorsB<Tvec, Kern>(context, solver_config, storage)
2199 // .update_divB();
2200 // }
2201
2202 // if (solver_config.has_field_curlB()) {
2203 // sph::modules::DiffOperatorsB<Tvec, Kern>(context, solver_config, storage)
2204 // .update_curlB();
2205 // }
2207
2208 if (solver_config.has_field_alphaAV()) {
2209
2211 = shambase::get_check_ref(storage.alpha_av_updated);
2212
2213 using InterfaceBuildInfos =
2215
2216 shambase::Timer time_interf;
2217 time_interf.start();
2218
2219 auto field_interf = ghost_handle.template build_interface_native<PatchDataField<Tscal>>(
2220 storage.ghost_patch_cache.get(),
2221 [&](u64 sender,
2222 u64 /*receiver*/,
2223 InterfaceBuildInfos binfo,
2224 sham::DeviceBuffer<u32> &buf_idx,
2225 u32 cnt) -> PatchDataField<Tscal> {
2226 PatchDataField<Tscal> &sender_field = comp_field_send.get_field(sender);
2227
2228 return sender_field.make_new_from_subset(buf_idx, cnt);
2229 });
2230
2232 = ghost_handle.communicate_pdatfield(
2233 std::move(field_interf), 1, storage.exchange_gz_alpha);
2234
2236 = ghost_handle.template merge_native<PatchDataField<Tscal>, PatchDataField<Tscal>>(
2237 std::move(interf_pdat),
2239 PatchDataField<Tscal> &receiver_field
2240 = comp_field_send.get_field(p.id_patch);
2241 return receiver_field.duplicate();
2242 },
2243 [](PatchDataField<Tscal> &mpdat, PatchDataField<Tscal> &pdat_interf) {
2244 mpdat.insert(pdat_interf);
2245 });
2246
2247 time_interf.stop();
2248 storage.timings_details.interface += time_interf.elapsed_sec();
2249
2250 storage.alpha_av_ghost.set(std::move(merged_field));
2251 }
2252
2253 // compute pressure
2255
2256 constexpr bool debug_interfaces = false;
2257 if constexpr (debug_interfaces) {
2258
2259 if (solver_config.do_debug_dump) {
2260
2262 = storage.merged_patchdata_ghost.get();
2263
2264 scheduler().for_each_patchdata_nonempty([&](Patch cur_p, PatchDataLayer &pdat) {
2265 MergedPatchData &merged_patch = mpdat.get(cur_p.id_patch);
2266 PatchDataLayer &mpdat = merged_patch.pdat;
2267
2268 sycl::buffer<Tvec> &buf_xyz = shambase::get_check_ref(
2269 merged_xyzh.get(cur_p.id_patch).field_pos.get_buf());
2270 sycl::buffer<Tvec> &buf_vxyz = mpdat.get_field_buf_ref<Tvec>(ivxyz_interf);
2271 sycl::buffer<Tscal> &buf_hpart = mpdat.get_field_buf_ref<Tscal>(ihpart_interf);
2272
2273 u32 total_elements = shambase::get_check_ref(storage.part_counts_with_ghost)
2274 .indexes.get(cur_p.id_patch);
2275 SHAM_ASSERT(merged_patch.total_elements == total_elements);
2276
2278 total_elements,
2279 solver_config.gpart_mass,
2280
2281 buf_xyz,
2282 buf_hpart,
2283 buf_vxyz};
2284
2285 make_interface_debug_phantom_dump(info).gen_file().write_to_file(
2286 solver_config.debug_dump_filename);
2287 logger::raw_ln("writing : ", solver_config.debug_dump_filename);
2288 });
2289 }
2290 }
2291
2292 // compute force
2293 shamlog_debug_ln("sph::BasicGas", "compute force");
2294
2295 // save old acceleration
2297
2298 update_derivs(dt);
2299
2300 bool has_luminosity = solver_config.compute_luminosity;
2301
2302 if (has_luminosity) {
2303 const u32 iluminosity = pdl.get_field_idx<Tscal>("luminosity");
2304
2305 shambase::get_check_ref(storage.hpart_with_ghosts)
2306 .set_refs(storage.merged_xyzh.get()
2307 .template map<std::reference_wrapper<PatchDataField<Tscal>>>(
2308 [&](u64 id, shamrock::patch::PatchDataLayer &mpdat) {
2309 return std::ref(mpdat.get_field<Tscal>(
2310 1)); // hpart is at index 1 in merged_xyzh
2311 }));
2312
2313 auto uint_with_ghost = shamrock::solvergraph::FieldRefs<Tscal>::make_shared("", "");
2314
2315 shambase::get_check_ref(storage.hpart_with_ghosts)
2316 .set_refs(storage.merged_xyzh.get()
2317 .template map<std::reference_wrapper<PatchDataField<Tscal>>>(
2318 [&](u64 id, shamrock::patch::PatchDataLayer &mpdat) {
2319 return std::ref(mpdat.get_field<Tscal>(1));
2320 }));
2321
2323 set_uint_with_ghost_refs(
2324 [&](shamrock::solvergraph::FieldRefs<Tscal> &field_uint_with_ghost_edge) {
2326 = storage.merged_patchdata_ghost.get();
2327
2328 shamrock::solvergraph::DDPatchDataFieldRef<Tscal> field_uint_with_ghost_refs
2329 = {};
2330
2331 scheduler().for_each_patchdata_nonempty(
2332 [&](const Patch p, PatchDataLayer &pdat) {
2333 PatchDataLayer &mpdat = mpdats.get(p.id_patch);
2334
2335 auto &field = mpdat.get_field<Tscal>(iuint_interf);
2336 field_uint_with_ghost_refs.add_obj(p.id_patch, std::ref(field));
2337 });
2338
2339 field_uint_with_ghost_edge.set_refs(field_uint_with_ghost_refs);
2340 });
2341
2342 set_uint_with_ghost_refs.set_edges(uint_with_ghost);
2343
2344 auto luminosity = shamrock::solvergraph::FieldRefs<Tscal>::make_shared("", "");
2345
2347 set_luminosity_refs(
2348 [&](shamrock::solvergraph::FieldRefs<Tscal> &field_luminosity_edge) {
2350 = storage.merged_patchdata_ghost.get();
2351
2353 = {};
2354
2355 scheduler().for_each_patchdata_nonempty(
2356 [&](const Patch p, PatchDataLayer &pdat) {
2357 auto &field = pdat.get_field<Tscal>(iluminosity);
2358 field_luminosity_refs.add_obj(p.id_patch, std::ref(field));
2359 });
2360 field_luminosity_edge.set_refs(field_luminosity_refs);
2361 });
2362
2363 set_luminosity_refs.set_edges(luminosity);
2364
2365 set_uint_with_ghost_refs.evaluate();
2366 set_luminosity_refs.evaluate();
2367
2368 Tscal alpha_u = solver_config.artif_viscosity.get_alpha_u().value();
2369
2371 solver_config.gpart_mass, alpha_u};
2372
2373 compute_luminosity.set_edges(
2374 storage.part_counts,
2375 storage.neigh_cache,
2376 storage.positions_with_ghosts,
2377 storage.hpart_with_ghosts,
2378 storage.omega,
2379 uint_with_ghost,
2380 storage.pressure,
2381 luminosity);
2382
2383 compute_luminosity.evaluate();
2384 }
2385
2386 modules::ConservativeCheck<Tvec, Kern> cv_check(context, solver_config, storage);
2387 cv_check.check_conservation();
2388
2389 ComputeField<Tscal> vepsilon_v_sq
2390 = utility.make_compute_field<Tscal>("vmean epsilon_v^2", 1);
2391 ComputeField<Tscal> uepsilon_u_sq
2392 = utility.make_compute_field<Tscal>("umean epsilon_u^2", 1);
2393
2394 // corrector
2395 shamlog_debug_ln("sph::BasicGas", "leapfrog corrector");
2396 utility.fields_leapfrog_corrector<Tvec>(
2397 ivxyz, iaxyz, storage.old_axyz.get(), vepsilon_v_sq, dt / 2);
2398 utility.fields_leapfrog_corrector<Tscal>(
2399 iuint, iduint, storage.old_duint.get(), uepsilon_u_sq, dt / 2);
2400
2401 if (solver_config.has_field_B_on_rho()) {
2402 ComputeField<Tscal> BOR_epsilon_BOR_sq
2403 = utility.make_compute_field<Tscal>("B/rho epsilon_B/rho^2", 1);
2404 utility.fields_leapfrog_corrector<Tvec>(
2405 iB_on_rho, idB_on_rho, storage.old_dB_on_rho.get(), BOR_epsilon_BOR_sq, dt / 2);
2406 }
2407 if (solver_config.has_field_B_on_rho()) {
2408 ComputeField<Tscal> POC_epsilon_POC_sq
2409 = utility.make_compute_field<Tscal>("psi/ch epsilon_psi/ch^2", 1);
2410 utility.fields_leapfrog_corrector<Tscal>(
2411 ipsi_on_ch, idpsi_on_ch, storage.old_dpsi_on_ch.get(), POC_epsilon_POC_sq, dt / 2);
2412 }
2413
2414 if (solver_config.dust_config.has_epsilon_field()) {
2415 ComputeField<Tscal> epsilon_epsilon_sq
2416 = utility.make_compute_field<Tscal>("epsilon epsilon^2", 1);
2417 utility.fields_leapfrog_corrector<Tscal>(
2418 iepsilon, idtepsilon, storage.old_dtepsilon.get(), epsilon_epsilon_sq, dt / 2);
2419 }
2420
2421 if (solver_config.dust_config.has_deltav_field()) {
2422 ComputeField<Tscal> epsilon_deltav_sq
2423 = utility.make_compute_field<Tscal>("deltav deltav^2", 1);
2424 utility.fields_leapfrog_corrector<Tvec>(
2425 ideltav, idtdeltav, storage.old_dtdeltav.get(), epsilon_deltav_sq, dt / 2);
2426 }
2427
2428 if (solver_config.dust_config.has_s_j_field()) {
2429 ComputeField<Tscal> s_j_s_j_sq = utility.make_compute_field<Tscal>(
2430 "s_j s_j^2", solver_config.dust_config.get_dust_nvar());
2431 bool ensure_positivity
2432 = solver_config.dust_config.get_monofluid_tva().ensure_s_j_positivity;
2433 if (ensure_positivity) {
2434 utility.fields_leapfrog_corrector_positive_only<Tscal>(
2435 is_j, ids_j_dt, storage.old_ds_j_dt.get(), s_j_s_j_sq, dt / 2);
2436 } else {
2437 utility.fields_leapfrog_corrector<Tscal>(
2438 is_j, ids_j_dt, storage.old_ds_j_dt.get(), s_j_s_j_sq, dt / 2);
2439 }
2440 }
2441
2442 storage.old_axyz.reset();
2443 storage.old_duint.reset();
2444 if (solver_config.has_field_B_on_rho()) {
2445 storage.old_dB_on_rho.reset();
2446 }
2447 if (solver_config.has_field_B_on_rho()) {
2448 storage.old_dpsi_on_ch.reset();
2449 }
2450
2451 if (solver_config.dust_config.has_epsilon_field()) {
2452 storage.old_dtepsilon.reset();
2453 }
2454
2455 if (solver_config.dust_config.has_deltav_field()) {
2456 storage.old_dtdeltav.reset();
2457 }
2458
2459 if (solver_config.dust_config.has_s_j_field()) {
2460 storage.old_ds_j_dt.reset();
2461 }
2462
2463 Tscal rank_veps_v = sycl::sqrt(vepsilon_v_sq.compute_rank_max());
2465 // compute means //////////////////////////
2467
2468 Tscal sum_vsq = utility.compute_rank_dot_sum<Tvec>(ivxyz);
2469
2470 Tscal vmean_sq = shamalgs::collective::allreduce_sum(sum_vsq) / Tscal(Npart_all);
2471
2472 Tscal vmean = sycl::sqrt(vmean_sq);
2473
2474 Tscal rank_eps_v = rank_veps_v / vmean;
2475
2476 if (vmean <= 0) {
2477 rank_eps_v = 0;
2478 }
2479
2480 Tscal eps_v = shamalgs::collective::allreduce_max(rank_eps_v);
2481
2482 shamlog_debug_ln("BasicGas", "epsilon v :", eps_v);
2483
2484 if (eps_v > 1e-2) {
2485 if (shamcomm::world_rank() == 0) {
2487 "BasicGasSPH",
2488 shambase::format(
2489 "the corrector tolerance are broken the step will "
2490 "be re rerunned\n eps_v = {}",
2491 eps_v));
2492 }
2493 need_rerun_corrector = true;
2494 set_cfl_multipler(get_cfl_multipler() / 2);
2495
2496 // logger::info_ln("rerun corrector ...");
2497 } else {
2498 need_rerun_corrector = false;
2499 }
2500
2501 if (!need_rerun_corrector) {
2502
2503 sink_update.corrector_step(dt);
2504
2505 // write back alpha av field
2506 if (solver_config.has_field_alphaAV()) {
2507
2508 const u32 ialpha_AV = pdl.get_field_idx<Tscal>("alpha_AV");
2509 shamrock::solvergraph::Field<Tscal> &alpha_av_updated
2510 = shambase::get_check_ref(storage.alpha_av_updated);
2511
2512 scheduler().for_each_patchdata_nonempty([&](Patch cur_p, PatchDataLayer &pdat) {
2513 sham::DeviceBuffer<Tscal> &buf_alpha_av
2514 = pdat.get_field<Tscal>(ialpha_AV).get_buf();
2515 sham::DeviceBuffer<Tscal> &buf_alpha_av_updated
2516 = alpha_av_updated.get_field(cur_p.id_patch).get_buf();
2517
2518 auto &q = shamsys::instance::get_compute_scheduler().get_queue();
2519 sham::EventList depends_list;
2520
2521 auto alpha_av = buf_alpha_av.get_write_access(depends_list);
2522 auto alpha_av_updated = buf_alpha_av_updated.get_read_access(depends_list);
2523
2524 auto e = q.submit(depends_list, [&](sycl::handler &cgh) {
2525 shambase::parallel_for(
2526 cgh, pdat.get_obj_cnt(), "write back alpha_av", [=](i32 id_a) {
2527 alpha_av[id_a] = alpha_av_updated[id_a];
2528 });
2529 });
2530
2531 buf_alpha_av.complete_event_state(e);
2532 buf_alpha_av_updated.complete_event_state(e);
2533 });
2534 }
2535
2536 shamlog_debug_ln("BasicGas", "computing next CFL");
2537
2538 // Update element counts
2539 shambase::get_check_ref(storage.part_counts).indexes
2540 = storage.merged_xyzh.get().template map<u32>(
2541 [&](u64 id, shamrock::patch::PatchDataLayer &mpdat) {
2542 return scheduler().patch_data.get_pdat(id).get_obj_cnt();
2543 });
2544
2545 std::shared_ptr<shamrock::solvergraph::Field<Tscal>> vsig_max_dt
2546 = std::make_shared<shamrock::solvergraph::Field<Tscal>>(
2547 1, "vsig_a", "v_{\\rm sig}");
2548 vsig_max_dt->ensure_sizes(shambase::get_check_ref(storage.part_counts).indexes);
2549
2550 std::shared_ptr<shamrock::solvergraph::Field<Tscal>> vclean_dt;
2551 if (has_psi_field) {
2552 vclean_dt = std::make_shared<shamrock::solvergraph::Field<Tscal>>(
2553 1, "vclean_a", "v_{\\rm clean}");
2554 vclean_dt->ensure_sizes(shambase::get_check_ref(storage.part_counts).indexes);
2555 }
2556
2558 = storage.merged_patchdata_ghost.get();
2559
2560 scheduler().for_each_patchdata_nonempty([&](Patch cur_p, PatchDataLayer &pdat) {
2561 PatchDataLayer &mpdat = mpdats.get(cur_p.id_patch);
2562
2564 = merged_xyzh.get(cur_p.id_patch).template get_field_buf_ref<Tvec>(0);
2565 sham::DeviceBuffer<Tvec> &buf_vxyz = mpdat.get_field_buf_ref<Tvec>(ivxyz_interf);
2566 sham::DeviceBuffer<Tscal> &buf_hpart
2567 = mpdat.get_field_buf_ref<Tscal>(ihpart_interf);
2568 sham::DeviceBuffer<Tscal> &buf_uint = mpdat.get_field_buf_ref<Tscal>(iuint_interf);
2569 sham::DeviceBuffer<Tscal> &buf_pressure
2570 = shambase::get_check_ref(storage.pressure).get_field(cur_p.id_patch).get_buf();
2571 sham::DeviceBuffer<Tscal> &cs_buf = shambase::get_check_ref(storage.soundspeed)
2572 .get_field(cur_p.id_patch)
2573 .get_buf();
2574
2575 sham::DeviceBuffer<Tscal> &vsig_buf = vsig_max_dt->get_buf(cur_p.id_patch);
2576
2577 sycl::range range_npart{pdat.get_obj_cnt()};
2578
2579 tree::ObjectCache &pcache
2580 = shambase::get_check_ref(storage.neigh_cache).get_cache(cur_p.id_patch);
2581
2583
2584 {
2585
2586 auto &q = shamsys::instance::get_compute_scheduler().get_queue();
2587 sham::EventList depends_list;
2588
2589 auto xyz = buf_xyz.get_read_access(depends_list);
2590 auto vxyz = buf_vxyz.get_read_access(depends_list);
2591 auto hpart = buf_hpart.get_read_access(depends_list);
2592 auto u = buf_uint.get_read_access(depends_list);
2593 auto pressure = buf_pressure.get_read_access(depends_list);
2594 auto cs = cs_buf.get_read_access(depends_list);
2595 auto vsig = vsig_buf.get_write_access(depends_list);
2596 auto particle_looper_ptrs = pcache.get_read_access(depends_list);
2597
2598 NamedStackEntry tmppp{"compute vsig"};
2599 auto e = q.submit(depends_list, [&](sycl::handler &cgh) {
2600 const Tscal pmass = solver_config.gpart_mass;
2601 const Tscal alpha_u = 1.0;
2602 const Tscal alpha_AV = 1.0;
2603 const Tscal beta_AV = 2.0;
2604
2605 tree::ObjectCacheIterator particle_looper(particle_looper_ptrs);
2606
2607 constexpr Tscal Rker2 = Kernel::Rkern * Kernel::Rkern;
2608
2609 shambase::parallel_for(
2610 cgh, pdat.get_obj_cnt(), "compute vsig", [=](i32 id_a) {
2611 using namespace shamrock::sph;
2612
2613 Tvec sum_axyz = {0, 0, 0};
2614 Tscal sum_du_a = 0;
2615 Tscal h_a = hpart[id_a];
2616
2617 Tvec xyz_a = xyz[id_a];
2618 Tvec vxyz_a = vxyz[id_a];
2619
2620 Tscal rho_a = rho_h(pmass, h_a, Kernel::hfactd);
2621 Tscal rho_a_sq = rho_a * rho_a;
2622 Tscal rho_a_inv = 1. / rho_a;
2623
2624 Tscal P_a = pressure[id_a];
2625
2626 const Tscal u_a = u[id_a];
2627
2628 Tscal cs_a = cs[id_a];
2629
2630 Tscal vsig_max = 0;
2631
2632 particle_looper.for_each_object(id_a, [&](u32 id_b) {
2633 // compute only omega_a
2634 Tvec dr = xyz_a - xyz[id_b];
2635 Tscal rab2 = sycl::dot(dr, dr);
2636 Tscal h_b = hpart[id_b];
2637
2638 if (rab2 > h_a * h_a * Rker2 && rab2 > h_b * h_b * Rker2) {
2639 return;
2640 }
2641
2642 Tscal rab = sycl::sqrt(rab2);
2643 Tvec vxyz_b = vxyz[id_b];
2644 Tvec v_ab = vxyz_a - vxyz_b;
2645 const Tscal u_b = u[id_b];
2646
2647 Tvec r_ab_unit = dr / rab;
2648
2649 if (rab < 1e-9) {
2650 r_ab_unit = {0, 0, 0};
2651 }
2652
2653 Tscal rho_b = rho_h(pmass, h_b, Kernel::hfactd);
2654 Tscal P_b = pressure[id_b];
2655 Tscal cs_b = cs[id_b];
2656 Tscal v_ab_r_ab = sycl::dot(v_ab, r_ab_unit);
2657 Tscal abs_v_ab_r_ab = sycl::fabs(v_ab_r_ab);
2658
2660 // internal energy update
2661 // scalar : f32 | vector : f32_3
2662 const Tscal alpha_a = alpha_AV;
2663 const Tscal alpha_b = alpha_AV;
2664
2665 Tscal vsig_a = alpha_a * cs_a + beta_AV * abs_v_ab_r_ab;
2666
2667 vsig_max = sycl::fmax(vsig_max, vsig_a);
2668 });
2669
2670 vsig[id_a] = vsig_max;
2671 });
2672 });
2673
2674 if (has_psi_field) {
2675 NamedStackEntry tmppp{"compute vclean"};
2676 Tscal const mu_0 = solver_config.get_constant_mu_0();
2677 sham::DeviceBuffer<Tscal> &vclean_buf = vclean_dt->get_buf(cur_p.id_patch);
2678
2679 Tvec *B_on_rho = mpdat.get_field_buf_ref<Tvec>(iB_on_rho_interf)
2680 .get_write_access(depends_list);
2681
2682 auto vclean = vclean_buf.get_write_access(depends_list);
2683
2684 auto e = q.submit(depends_list, [&](sycl::handler &cgh) {
2685 const Tscal pmass = solver_config.gpart_mass;
2686
2687 tree::ObjectCacheIterator particle_looper(particle_looper_ptrs);
2688
2689 constexpr Tscal Rker2 = Kernel::Rkern * Kernel::Rkern;
2690
2691 shambase::parallel_for(
2692 cgh, pdat.get_obj_cnt(), "compute vclean", [=](i32 id_a) {
2693 using namespace shamrock::sph;
2694
2695 Tscal h_a = hpart[id_a];
2696 Tscal rho_a = rho_h(pmass, h_a, Kernel::hfactd);
2697 const Tscal u_a = u[id_a];
2698 Tscal cs_a = cs[id_a];
2699 Tvec B_a = B_on_rho[id_a] * rho_a;
2700
2701 Tscal vclean_a = shamphys::MHD_physics<Tvec, Tscal>::v_shock(
2702 cs_a, B_a, rho_a, mu_0);
2703
2704 vclean[id_a] = vclean_a;
2705 });
2706 });
2707 mpdat.get_field_buf_ref<Tvec>(iB_on_rho_interf).complete_event_state(e);
2708 vclean_buf.complete_event_state(e);
2709 };
2710
2711 buf_xyz.complete_event_state(e);
2712 buf_vxyz.complete_event_state(e);
2713 buf_hpart.complete_event_state(e);
2714 buf_uint.complete_event_state(e);
2715 buf_pressure.complete_event_state(e);
2716 cs_buf.complete_event_state(e);
2717 vsig_buf.complete_event_state(e);
2718
2719 sham::EventList resulting_events;
2720 resulting_events.add_event(e);
2721 pcache.complete_event_state(resulting_events);
2722 }
2723 });
2724
2725 std::shared_ptr<shamrock::solvergraph::Field<Tscal>> cfl_dt
2726 = std::make_shared<shamrock::solvergraph::Field<Tscal>>(
2727 1, "cfl_dt", "\\Delta t_{cfl}");
2728 cfl_dt->ensure_sizes(shambase::get_check_ref(storage.part_counts).indexes);
2729
2730 std::shared_ptr<shamrock::solvergraph::FieldRefs<Tvec>> axyz_refs
2731 = std::make_shared<shamrock::solvergraph::FieldRefs<Tvec>>("axyz", "\\mathbf{a}");
2732 std::shared_ptr<shamrock::solvergraph::FieldRefs<Tscal>> hpart_refs
2733 = std::make_shared<shamrock::solvergraph::FieldRefs<Tscal>>("hpart", "h");
2734
2735 map_field_refs(scheduler(), iaxyz, *axyz_refs);
2736 map_field_refs_ext(scheduler(), mpdats, ihpart_interf, *hpart_refs);
2737
2738 auto &q = shamsys::instance::get_compute_scheduler().get_queue();
2739
2740 auto reset_dt_part_field = [&]() {
2741 if (solver_config.should_save_dt_to_fields()) {
2742 const u32 idt_part = pdl.get_field_idx<Tscal>("dt_part");
2743 scheduler().for_each_patchdata_nonempty([&](Patch cur_p, PatchDataLayer &pdat) {
2744 sham::DeviceBuffer<Tscal> &buf_dt_part
2745 = pdat.get_field_buf_ref<Tscal>(idt_part);
2746 buf_dt_part.fill(shambase::get_infty<Tscal>());
2747 });
2748 }
2749 };
2750
2751 auto save_dt_min_to_dt_part = [&]() {
2752 if (solver_config.should_save_dt_to_fields()) {
2753 const u32 idt_part = pdl.get_field_idx<Tscal>("dt_part");
2754 scheduler().for_each_patchdata_nonempty([&](Patch cur_p, PatchDataLayer &pdat) {
2755 sham::DeviceBuffer<Tscal> &buf_dt_part
2756 = pdat.get_field_buf_ref<Tscal>(idt_part);
2757 sham::DeviceBuffer<Tscal> &buf_dt = cfl_dt->get_buf(cur_p.id_patch);
2758
2760 q,
2761 sham::MultiRef{buf_dt},
2762 sham::MultiRef{buf_dt_part},
2763 pdat.get_obj_cnt(),
2764 [](u32 id_a, const Tscal *dt, Tscal *dt_part) {
2765 dt_part[id_a] = sycl::min(dt_part[id_a], dt[id_a]);
2766 });
2767 });
2768 }
2769 };
2770
2771 // reset the cfl_dt field
2772 auto reset_cfl_dt = [&]() {
2773 scheduler().for_each_patchdata_nonempty([&](Patch cur_p, PatchDataLayer &pdat) {
2774 cfl_dt->get_buf(cur_p.id_patch).fill(shambase::get_infty<Tscal>());
2775 });
2776 };
2777
2778 Tscal C_cour = solver_config.cfl_config.cfl_cour * get_cfl_multipler();
2779 Tscal C_force = solver_config.cfl_config.cfl_force * get_cfl_multipler();
2780 Tscal eta_phi = solver_config.cfl_config.eta_sink;
2781
2782 std::shared_ptr<shamrock::solvergraph::ScalarEdge<Tscal>> C_cour_edge
2783 = std::make_shared<shamrock::solvergraph::ScalarEdge<Tscal>>("C_cour", "C_{cour}");
2784 C_cour_edge->value = C_cour;
2785 std::shared_ptr<shamrock::solvergraph::ScalarEdge<Tscal>> C_force_edge
2786 = std::make_shared<shamrock::solvergraph::ScalarEdge<Tscal>>(
2787 "C_force", "C_{force}");
2788 C_force_edge->value = C_force;
2789 std::shared_ptr<shamrock::solvergraph::ScalarEdge<Tscal>> eta_phi_edge
2790 = std::make_shared<shamrock::solvergraph::ScalarEdge<Tscal>>(
2791 "eta_phi", "\\eta_{\\phi}");
2792 eta_phi_edge->value = eta_phi;
2793
2794 std::shared_ptr<ComputeCFLCourant<Tscal>> compute_cfl_courant
2795 = std::make_shared<ComputeCFLCourant<Tscal>>();
2796 compute_cfl_courant->set_edges(
2797 storage.part_counts, C_cour_edge, hpart_refs, vsig_max_dt, cfl_dt);
2798
2799 std::shared_ptr<ComputeCFLForce<Tvec>> compute_cfl_force
2800 = std::make_shared<ComputeCFLForce<Tvec>>();
2801 compute_cfl_force->set_edges(
2802 storage.part_counts, C_force_edge, hpart_refs, axyz_refs, cfl_dt);
2803
2804 std::shared_ptr<ComputeCFLDivBCleaning<Tscal>> compute_cfl_divB_cleaning;
2805 if (has_psi_field) {
2806 compute_cfl_divB_cleaning = std::make_shared<ComputeCFLDivBCleaning<Tscal>>();
2807 compute_cfl_divB_cleaning->set_edges(
2808 storage.part_counts, C_cour_edge, hpart_refs, vclean_dt, cfl_dt);
2809 }
2810
2811 std::shared_ptr<ComputeCFLDust1Fluid<Tvec>> compute_cfl_dust1_fluid;
2812 std::shared_ptr<shamrock::solvergraph::FieldRefs<Tscal>> s_j_refs;
2813 std::shared_ptr<shamrock::solvergraph::ScalarEdge<Tscal>> hfactd_edge;
2814
2815 if (solver_config.dust_config.has_s_j_field()) {
2816 u32 ndust = solver_config.dust_config.get_dust_nvar();
2817
2818 compute_cfl_dust1_fluid = std::make_shared<ComputeCFLDust1Fluid<Tvec>>(ndust);
2819
2820 auto t_j_field
2821 = storage.solver_graph
2822 .template get_edge_ptr<shamrock::solvergraph::Field<Tscal>>("Ts_j");
2823
2824 auto pmass_edge
2825 = storage.solver_graph
2826 .template get_edge_ptr<shamrock::solvergraph::ScalarEdge<Tscal>>(
2827 "gpart_mass");
2828
2829 s_j_refs = std::make_shared<shamrock::solvergraph::FieldRefs<Tscal>>("s_j", "s_j");
2830
2831 hfactd_edge = std::make_shared<shamrock::solvergraph::ScalarEdge<Tscal>>(
2832 "hfactd", "hfactd");
2833 hfactd_edge->value = Kernel::hfactd;
2834
2835 map_field_refs(scheduler(), is_j, *s_j_refs);
2836
2837 std::shared_ptr<shamrock::solvergraph::ScalarEdge<Tscal>> C_1fluid_edge
2838 = std::make_shared<shamrock::solvergraph::ScalarEdge<Tscal>>(
2839 "C_1fluid", "C_{1fluid}");
2840 C_1fluid_edge->value
2841 = solver_config.dust_config.get_monofluid_tva().C_1_fluid * get_cfl_multipler();
2842
2843 compute_cfl_dust1_fluid->set_edges(
2844 storage.part_counts,
2845 C_1fluid_edge,
2846 pmass_edge,
2847 hfactd_edge,
2848 hpart_refs,
2849 storage.soundspeed,
2850 s_j_refs,
2851 t_j_field,
2852 cfl_dt);
2853 }
2854
2855 std::shared_ptr<ComputeCFLDustDrift<Tvec>> compute_cfl_dust_drift;
2856 std::shared_ptr<shamrock::solvergraph::ScalarEdge<Tscal>> C_drift_edge;
2857 std::shared_ptr<shamrock::solvergraph::ScalarEdge<Tscal>> cfl_density_threshold_edge;
2858 std::shared_ptr<shamrock::solvergraph::FieldRefs<Tvec>> delta_v_refs;
2859
2860 if (solver_config.dust_config.has_s_j_field()) {
2861 u32 ndust = solver_config.dust_config.get_dust_nvar();
2862
2863 compute_cfl_dust_drift = std::make_shared<ComputeCFLDustDrift<Tvec>>(ndust);
2864
2865 delta_v_refs = std::make_shared<shamrock::solvergraph::FieldRefs<Tvec>>(
2866 "delta_v", "delta_v");
2867 const u32 idelta_v = pdl.get_field_idx<Tvec>("delta_v");
2868 map_field_refs(scheduler(), idelta_v, *delta_v_refs);
2869
2870 auto &cfg_monofluid_tva = solver_config.dust_config.get_monofluid_tva();
2871
2872 C_drift_edge = std::make_shared<shamrock::solvergraph::ScalarEdge<Tscal>>(
2873 "C_drift", "C_{drift}");
2874 C_drift_edge->value = cfg_monofluid_tva.C_drift * get_cfl_multipler();
2875
2876 cfl_density_threshold_edge
2877 = std::make_shared<shamrock::solvergraph::ScalarEdge<Tscal>>(
2878 "cfl_density_threshold", "cfl_density_threshold");
2879 cfl_density_threshold_edge->value = cfg_monofluid_tva.cfl_density_threshold;
2880
2881 auto pmass_edge
2882 = storage.solver_graph
2883 .template get_edge_ptr<shamrock::solvergraph::ScalarEdge<Tscal>>(
2884 "gpart_mass");
2885
2886 compute_cfl_dust_drift->set_edges(
2887 storage.part_counts,
2888 C_drift_edge,
2889 cfl_density_threshold_edge,
2890 pmass_edge,
2891 hfactd_edge,
2892 hpart_refs,
2893 s_j_refs,
2894 delta_v_refs,
2895 cfl_dt);
2896 }
2897
2898 bool show_cfl_detail = solver_config.show_cfl_detail;
2899 std::vector<std::pair<std::string, Tscal>> cfl_detail;
2900
2901 auto save_cfl_detail = [&](const char *key) {
2902 if (show_cfl_detail) {
2903 save_dt_min_to_dt_part();
2904 cfl_detail.push_back(
2905 {std::string(key), cfl_dt->get_native().compute_rank_min()});
2906 reset_cfl_dt();
2907 }
2908 };
2909
2910 reset_dt_part_field();
2911 reset_cfl_dt();
2912
2913 compute_cfl_courant->evaluate();
2914 save_cfl_detail("courant");
2915
2916 compute_cfl_force->evaluate();
2917 save_cfl_detail("force");
2918
2919 if (has_psi_field) {
2920 compute_cfl_divB_cleaning->evaluate();
2921 save_cfl_detail("divB_cleaning");
2922 }
2923
2924 if (solver_config.dust_config.has_s_j_field()) {
2925 compute_cfl_dust1_fluid->evaluate();
2926 save_cfl_detail("dust1_fluid");
2927
2928 compute_cfl_dust_drift->evaluate();
2929 save_cfl_detail("dust_drift");
2930 }
2931
2932 if (!show_cfl_detail) {
2933 save_dt_min_to_dt_part();
2934 cfl_detail.push_back({"all SPH", cfl_dt->get_native().compute_rank_min()});
2935 }
2936
2937 auto &sync = scheduler().synchronized_data;
2938 auto &pos = get_sink_pos<Tvec>(sync);
2939 if (!pos.empty()) {
2940 // sink sink CFL
2941
2942 Tscal sink_sink_cfl = shambase::get_infty<Tscal>();
2943
2944 Tscal G = solver_config.get_constant_G();
2945
2946 auto &mass = get_sink_mass<Tvec>(sync);
2947 auto &acc_ext = get_sink_acc_ext<Tvec>(sync);
2948
2949 for (u32 i = 0; i < pos.size(); i++) {
2950 Tscal sink_sink_cfl_i = shambase::get_infty<Tscal>();
2951
2952 Tvec f_i = acc_ext[i];
2953
2954 Tscal grad_phi_i_sq = sham::dot(f_i, f_i); // m^2.s^-4
2955
2956 if (grad_phi_i_sq == 0) {
2957 continue;
2958 }
2959
2960 for (u32 j = 0; j < pos.size(); j++) {
2961 if (i == j) {
2962 continue;
2963 }
2964
2965 Tvec rij = pos[i] - pos[j];
2966 Tscal rij_scal = sycl::length(rij);
2967
2968 Tscal phi_ij = G * mass[j] / rij_scal; // J / kg = m^2.s^-2
2969 Tscal term_ij = sham::abs(phi_ij) / grad_phi_i_sq; // s^2
2970 Tscal dt_ij = C_force * eta_phi * sycl::sqrt(term_ij); // s
2971
2972 sink_sink_cfl_i = sham::min(sink_sink_cfl_i, dt_ij);
2973 }
2974
2975 sink_sink_cfl = sham::min(sink_sink_cfl, sink_sink_cfl_i);
2976 }
2977
2978 cfl_detail.push_back({"sink_sink", sink_sink_cfl});
2979 }
2980
2981 Tscal rank_dt = shambase::get_infty<Tscal>();
2982 for (auto &[key, value] : cfl_detail) {
2983 rank_dt = sham::min(rank_dt, value);
2984 }
2985
2986 if (show_cfl_detail) {
2987 for (auto &[key, value] : cfl_detail) {
2988 value = shamalgs::collective::allreduce_min(value);
2989 }
2990
2991 if (shamcomm::world_rank() == 0) {
2992 shambase::table table(2);
2993 table.add_double_rule();
2994 table.add_data({"key", "value"}, shambase::table::center);
2995 table.add_double_rule();
2996 for (auto &[key, value] : cfl_detail) {
2997 table.add_data(
2998 {key, shambase::format("{:.2e}", value)}, shambase::table::right);
2999 }
3000 table.add_rule();
3001 logger::info_ln("sph::Model", "CFL detail :", table.render());
3002 }
3003 }
3004
3005 next_cfl = shamalgs::collective::allreduce_min(rank_dt);
3006
3007 if (shamcomm::world_rank() == 0) {
3009 "sph::Model", "cfl dt =", next_cfl, "cfl multiplier :", get_cfl_multipler());
3010 }
3011
3012 // this should not be needed idealy, but we need the pressure on the ghosts and
3013 // we don't want to communicate it as it can be recomputed from the other fields
3014 // hence we copy the soundspeed at the end of the step to a field in the patchdata
3015 if (solver_config.has_field_soundspeed()) {
3016
3017 const u32 isoundspeed = pdl.get_field_idx<Tscal>("soundspeed");
3018
3019 scheduler().for_each_patchdata_nonempty([&](Patch cur_p, PatchDataLayer &pdat) {
3020 sham::DeviceBuffer<Tscal> &buf_cs = pdat.get_field_buf_ref<Tscal>(isoundspeed);
3021 sham::DeviceBuffer<Tscal> &buf_cs_in
3022 = shambase::get_check_ref(storage.soundspeed)
3023 .get_field(cur_p.id_patch)
3024 .get_buf();
3025
3026 sycl::range range_npart{pdat.get_obj_cnt()};
3027
3029
3030 auto &q = shamsys::instance::get_compute_scheduler().get_queue();
3031 sham::EventList depends_list;
3032
3033 auto cs_in = buf_cs_in.get_read_access(depends_list);
3034 auto cs = buf_cs.get_write_access(depends_list);
3035
3036 auto e = q.submit(depends_list, [&](sycl::handler &cgh) {
3037 const Tscal pmass = solver_config.gpart_mass;
3038
3039 cgh.parallel_for(
3040 sycl::range<1>{pdat.get_obj_cnt()}, [=](sycl::item<1> item) {
3041 cs[item] = cs_in[item];
3042 });
3043 });
3044
3045 buf_cs_in.complete_event_state(e);
3046 buf_cs.complete_event_state(e);
3047 });
3048 }
3049
3050 } // if (!need_rerun_corrector) {
3051
3052 corrector_iter_cnt++;
3053
3054 if (solver_config.has_field_alphaAV()) {
3055 storage.alpha_av_ghost.reset();
3056 }
3057 } while (need_rerun_corrector);
3058
3059 reset_merge_ghosts_fields();
3060 reset_eos_fields();
3061
3062 // if delta too big jump to compute force
3063
3064 tstep.stop();
3065
3066 for (auto it = timestep_callbacks.rbegin(); it != timestep_callbacks.rend(); ++it) {
3067 if (it->step_end_callback) {
3068 shambase::get_check_ref(it->step_end_callback)();
3069 }
3070 }
3071
3072 f64 delta_mpi_timer = shamcomm::mpi::get_timer("total") - mpi_timer_start;
3074
3076 shamsys::SystemMetrics system_metrics_end = shamsys::get_system_metrics();
3077 shamsys::SystemMetrics system_metrics_delta = system_metrics_end - system_metrics_start;
3078
3079 f64 t_dev_alloc
3080 = (mem_perf_infos_end.time_alloc_device - mem_perf_infos_start.time_alloc_device)
3081 + (mem_perf_infos_end.time_free_device - mem_perf_infos_start.time_free_device);
3082 f64 t_host_alloc = (mem_perf_infos_end.time_alloc_host - mem_perf_infos_start.time_alloc_host)
3083 + (mem_perf_infos_end.time_free_host - mem_perf_infos_start.time_free_host);
3084
3085 u64 rank_count = scheduler().get_rank_count();
3086 f64 rate = f64(rank_count) / tstep.elapsed_sec();
3087
3088 u64 npatch = scheduler().patch_list.local.size();
3089
3090 // logger::info_ln("SPHSolver", "process rate : ", rate, "particle.s-1");
3091
3092 std::string log_step = report_perf_timestep(
3093 rate,
3094 rank_count,
3095 npatch,
3096 tstep.elapsed_sec(),
3097 delta_mpi_timer,
3098 t_dev_alloc,
3099 t_host_alloc,
3100 mem_perf_infos_end.max_allocated_byte_device,
3101 mem_perf_infos_end.max_allocated_byte_host,
3102 system_metrics_delta,
3103 shamsys::has_reporter());
3104
3105 if (shamcomm::world_rank() == 0) {
3106 logger::info_ln("sph::Model", log_step);
3108 "sph::Model", "estimated rate :", dt * (3600 / tstep.elapsed_sec()), "(tsim/hr)");
3109 }
3110
3111 solve_logs.register_log(
3112 {t_current, // f64 solver_t;
3113 dt, // f64 solver_dt;
3114 shamcomm::world_rank(), // i32 world_rank;
3115 rank_count, // u64 rank_count;
3116 rate, // f64 rate;
3117 tstep.elapsed_sec(), // f64 elapsed_sec;
3119 system_metrics_delta});
3120
3121 storage.timings_details.reset();
3122
3123 reset_serial_patch_tree();
3124 reset_ghost_handler();
3125
3126 shambase::get_check_ref(storage.part_counts).free_alloc();
3127 shambase::get_check_ref(storage.part_counts_with_ghost).free_alloc();
3128 shambase::get_check_ref(storage.positions_with_ghosts).free_alloc();
3129 shambase::get_check_ref(storage.hpart_with_ghosts).free_alloc();
3130 storage.merged_xyzh.reset();
3131 shambase::get_check_ref(storage.omega).free_alloc();
3132 clear_merged_pos_trees();
3133 clear_ghost_cache();
3134 reset_presteps_rint();
3135 reset_neighbors_cache();
3136
3137 shambase::get_check_ref(storage.neigh_cache).free_alloc();
3138
3139 set_next_dt(next_cfl);
3140 set_time(t_current + dt);
3141
3142 auto get_next_cfl_mult = [&]() {
3143 Tscal cfl_m = get_cfl_multipler();
3144 Tscal stiff = solver_config.cfl_config.cfl_multiplier_stiffness;
3145
3146 return (cfl_m * stiff + 1.) / (stiff + 1.);
3147 };
3148
3149 set_cfl_multipler(get_next_cfl_mult());
3150
3151 TimestepLog log;
3152 log.rank = shamcomm::world_rank();
3153 log.rate = rate;
3154 log.npart = rank_count;
3155 log.tcompute = tstep.elapsed_sec();
3156
3157 return log;
3158}
3159
3160using namespace shammath;
3161
3165
A module to compute and display statistics on neighbor counts for SPH particles.
Defines the CopyPatchDataFieldFromLayer class for copying fields between patch data layers.
Defines the DistributedBuffers class for managing distributed device buffers in a solver graph.
Implements a forward Euler integration step as a solver graph node.
Implements a forward Euler integration step as a solver graph node.
Defines the GetFieldRefFromLayer class for extracting field references from patch data layers.
Defines the GetObjCntFromLayer class for extracting object counts from patch data layers.
Declares the GetParticlesOutsideSphere module for removing particles.
shambase::DistributedData< PatchDataFieldRef< T > > DDPatchDataFieldRef
Alias for a DistributedData of PatchDataFieldRefs.
Declares the IterateSmoothingLengthDensityNeighLim module for iterating smoothing length based on the...
Declares the IterateSmoothingLengthDensity module for iterating smoothing length based on the SPH den...
Declares the KillParticles module for removing particles.
Declares the LoopSmoothingLengthIter module for looping over the smoothing length iteration until con...
Field variant object to instanciate a variant on the patch types.
Header file describing a Node Instance.
Node that maps a read-only input edge into a read-write output edge.
Node that applies a custom function to modify connected edges.
Defines the PatchDataLayerRefs class for managing distributed references to patch data layers.
MPI scheduler.
Header file for the patch struct and related function.
Declare a class to register and retrieve nodes and edges from a unique container.
double f64
Alias for double.
std::uint32_t u32
32 bit unsigned integer
std::uint64_t u64
64 bit unsigned integer
std::int32_t i32
32 bit integer
Shamrock assertion utility.
#define SHAM_ASSERT(x)
Shorthand for SHAM_ASSERT_NAMED without a message.
Definition assert.hpp:67
The MPI scheduler.
SynchronizedData synchronized_data
data that is synchroneous across all ranks
A buffer allocated in USM (Unified Shared Memory).
void complete_event_state(sycl::event e) const
Complete the event state of the buffer.
DeviceQueue & get_queue() const
Gets the DeviceQueue associated with the held allocation.
T * get_write_access(sham::EventList &depends_list, SourceLocation src_loc=SourceLocation{})
Get a read-write pointer to the buffer's data.
void fill(T value, std::array< size_t, 2 > idx_range)
Fill a subpart of the buffer with a given value.
const T * get_read_access(sham::EventList &depends_list, SourceLocation src_loc=SourceLocation{}) const
Get a read-only pointer to the buffer's data.
Class to manage a list of SYCL events.
Definition EventList.hpp:31
void add_event(sycl::event e)
Add an event to the list of events.
Definition EventList.hpp:87
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.
Represents a collection of objects distributed across patches identified by a u64 id.
iterator add_obj(u64 id, T &&obj)
Adds a new object to the collection.
DistributedData< Tmap > map(std::function< Tmap(u64, T &)> map_func)
Apply a function to all objects in the collection and return a new collection containing the results.
T & get(u64 id)
Returns a reference to an object in the collection.
Class Timer measures the time elapsed since the timer was started.
Definition Timer.hpp:36
f64 elapsed_sec() const
Converts the stored nanosecond time to a floating point representation in seconds.
Definition Timer.hpp:88
void start()
Starts the timer.
Definition Timer.hpp:51
void stop()
Stops the timer and stores the elapsed time in nanoseconds.
Definition Timer.hpp:65
Vector class based on std::array storage and mdspan.
Definition matrix.hpp:98
handle basic utilities dealing with SPH
The shamrock SPH model.
Definition Solver.hpp:71
void reset_presteps_rint()
Resets tree radius interval field.
Definition Solver.cpp:1242
void reset_merge_ghosts_fields()
Resets merged ghost field data.
Definition Solver.cpp:1519
void update_sync_load_values()
Updates load balancing values and synchronizes patch ownership.
Definition Solver.cpp:1818
bool apply_corrector(Tscal dt, u64 Npart_all)
Definition Solver.cpp:1813
void merge_position_ghost()
Merges ghost particle positions from neighboring patches.
Definition Solver.cpp:889
void reset_eos_fields()
Frees memory allocated for EOS fields.
Definition Solver.cpp:1545
void prepare_corrector()
Saves old derivative fields for predictor-corrector integration.
Definition Solver.cpp:1551
void build_ghost_cache()
Builds ghost particle interface cache for inter-patch communication.
Definition Solver.cpp:867
void update_artificial_viscosity(Tscal dt)
Updates artificial viscosity coefficients for shock capturing.
Definition Solver.cpp:1528
TimestepLog evolve_once()
Performs one complete SPH timestep evolution.
Definition Solver.cpp:1825
void vtk_do_dump(std::string filename, bool add_patch_world_id)
Writes VTK dump file for visualization.
Definition Solver.cpp:644
void update_derivs(Tscal dt_hydro)
Updates time derivatives and applies external forces.
Definition Solver.cpp:1647
void build_merged_pos_trees()
Builds spatial BVH trees for merged positions including ghosts.
Definition Solver.cpp:932
void clear_merged_pos_trees()
Clears merged position trees to free memory.
Definition Solver.cpp:937
void init_solver_graph()
Initializes the solver graph for computation pipeline.
Definition Solver.cpp:122
void sph_prestep(Tscal time_val, Tscal dt)
Performs pre-step operations for SPH timestep.
Definition Solver.cpp:943
void compute_presteps_rint()
Computes maximum smoothing length in tree nodes for neighbor search.
Definition Solver.cpp:1205
void compute_eos_fields()
Computes equation of state fields (pressure, sound speed).
Definition Solver.cpp:1539
void apply_position_boundary(Tscal time_val)
Applies position-based boundary conditions.
Definition Solver.cpp:821
void reset_neighbors_cache()
Resets neighbor cache.
Definition Solver.cpp:1272
void communicate_merge_ghosts_fields()
Communicates and merges ghost particle fields across processes.
Definition Solver.cpp:1277
void clear_ghost_cache()
Clears ghost particle cache to free memory.
Definition Solver.cpp:883
void init_ghost_layout()
Initializes data layout for ghost particle fields.
Definition Solver.cpp:1190
void start_neighbors_cache()
Builds neighbor particle cache for SPH calculations.
Definition Solver.cpp:1247
Module for constructing spatial tree structures for SPH neighbor searches.
void build_merged_pos_trees()
Builds compressed leaf BVH trees for merged particle positions including ghosts.
Module for computing equation of state quantities.
void compute_eos()
Computes pressure and sound speed from equation of state.
Module for checking conservation of physical quantities.
void check_conservation()
Verifies conservation of mass, momentum, and energy.
void add_ext_forces()
add external forces to the particle acceleration, note that forces dependant on velocity shlould be a...
void compute_ext_forces_indep_v()
is ran once per timestep, it computes the forces that are independant of velocity
Module for reordering particles to improve cache locality.
void reorder_particles()
Reorders particles by Morton code for improved memory access patterns.
Module for writing VTK format output files.
Definition VTKDump.hpp:33
void do_dump(std::string filename, bool add_patch_world_id)
Writes particle data to VTK file for visualization.
Definition VTKDump.cpp:37
Utility class used to move the objects between patches.
void reatribute_patch_objects(SerialPatchTree< T > &sptree, std::string position_field)
Reattribute objects based on a given position field.
ComputeField< T > make_compute_field(std::string new_name, u32 nvar)
create a compute field and init it to zeros
ComputeField< T > save_field(u32 field_idx, std::string new_name)
save a field in patchdata to a compute field
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 a solver graph edge representing a field as spans.
PatchDataField< T > & get_field(u64 id) const
Get the underlying PatchDataField at the given id.
void evaluate()
Evaluate the node.
Definition INode.hpp:146
A node that simply frees the allocation of the connected node.
A node that maps an input edge into an output edge.
A node that applies a custom function to modify connected edges.
void set_edges(std::shared_ptr< IEdge > to_set)
Set the edges of the node.
virtual void free_alloc() override
Free allocated memory.
A graph container for managing solver nodes and edges with type-safe access.
std::shared_ptr< INode > & get_node_ptr_base(const std::string &name)
Retrieve a node by name as a shared pointer to the base interface.
std::shared_ptr< T > get_edge_ptr(const std::string &name)
Get a typed shared pointer to an edge by name.
std::shared_ptr< T > register_edge(const std::string &name, T &&edge)
Register an edge with automatic type deduction and shared pointer creation.
std::shared_ptr< T > register_node(const std::string &name, T &&node)
Register a node with automatic type deduction and shared pointer creation.
INode & get_node_ref_base(const std::string &name)
Get a reference to a node by name through the base interface.
A Compressed Leaf Bounding Volume Hierarchy (CLBVH) for neighborhood queries.
A data structure representing a Karras Radix Tree Field.
This header file contains utility functions related to exception handling in the code.
MPI string gather / allgather helpers (declarations; implementations in shamalgs/src/collective/gathe...
MemPerfInfos get_mem_perf_info()
Retrieve the memory performance information.
This file contains the declaration of the memory handling and its methods.
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::vector< T > buf_to_vec(sycl::buffer< T > &buf, u32 len)
Convert a sycl::buffer to a std::vector.
Definition memory.cpp:34
void throw_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Throw an exception and append the source location to it.
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.
void throw_unimplemented(SourceLocation loc=SourceLocation{})
Throw a std::runtime_error saying that the function is unimplemented.
i32 world_rank()
Gives the rank of the current process in the MPI communicator.
Definition worldInfo.cpp:40
namespace for math utility
Definition AABB.hpp:26
namespace for the sph model
std::vector< Tvec > & get_sink_pos(shamrock::solvergraph::SolverGraphSerializable &sync)
Named SoA getters (edges must already exist; call ensure_sink_edges first). Prefer these when a funct...
namespace for the main framework
Definition __init__.py:1
void info(std::string module_name, Types... var2)
Prints a log message with multiple arguments.
Definition logs.hpp:133
void raw_ln(Types... var2)
Prints a log message with multiple arguments followed by a newline.
Definition logs.hpp:90
void info_ln(std::string module_name, Types... var2)
Prints a log message with multiple arguments followed by a newline.
Definition logs.hpp:133
void warn_ln(std::string module_name, Types... var2)
Prints a log message with multiple arguments followed by a newline.
Definition logs.hpp:133
void err_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.
file containing formulas for sph forces
sph kernels
shambase::details::NamedBasicStackEntry NamedStackEntry
Alias for shambase::details::NamedBasicStackEntry.
shambase::details::BasicStackEntry StackEntry
Alias for shambase::details::BasicStackEntry.
f64 get_wtime()
Returns the current wall clock time in seconds.
Structure to store the performance informations about memory allocation and deallocation.
f64 time_alloc_host
Time spent allocating memory on the host.
size_t max_allocated_byte_host
max bytes allocated on the host
f64 time_free_device
Time spent deallocating memory on the device.
size_t max_allocated_byte_device
max bytes allocated on the device
f64 time_alloc_device
Time spent allocating memory on the device.
f64 time_free_host
Time spent deallocating memory on the host.
A class that references multiple buffers or similar objects.
Definition MultiRef.hpp:33
A class to represent a single block of data in a Phantom dump.
u64 get_ref_f32(std::string s)
Gets the index of a block of type f32 with the given name.
u64 get_ref_fort_real(std::string s)
Gets the index of a block of type fort_real with the given name.
i64 tot_count
The total number of values in the block.
std::vector< PhantomDumpBlockArray< fort_real > > blocks_fort_real
The blocks of values of type fort_real.
std::vector< PhantomDumpBlockArray< f32 > > blocks_f32
The blocks of values of type f32.
Class representing a Phantom dump file.
void override_magic_number()
Overrides the magic numbers used in the PhantomDump struct.
BCConfig< Tvec > BCConfig
Configuration of the boundary conditions.
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.
f64 get_timer(std::string timername)
get a timer value
Definition wrapper.cpp:44