Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
Model.cpp
Go to the documentation of this file.
1// -------------------------------------------------------//
2//
3// SHAMROCK code for hydrodynamics
4// Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me>
5// SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1
6// Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information
7//
8// -------------------------------------------------------//
9
17
20#include "shambase/memory.hpp"
22#include "shambase/string.hpp"
24#include "shamcomm/logs.hpp"
39#include <functional>
40#include <random>
41#include <stdexcept>
42#include <utility>
43#include <vector>
44
45template<class Tvec, template<class> class SPHKernel>
46f64 shammodels::sph::Model<Tvec, SPHKernel>::evolve_once_time_expl(f64 t_curr, f64 dt_input) {
47 auto tmp = solver.evolve_once_time_expl(t_curr, dt_input);
48 solver.print_timestep_logs();
49 return tmp;
50}
51
52template<class Tvec, template<class> class SPHKernel>
53shammodels::sph::TimestepLog shammodels::sph::Model<Tvec, SPHKernel>::timestep() {
54 return solver.evolve_once();
55}
56
57template<class Tvec, template<class> class SPHKernel>
59
60 if (solver.solver_config.scheduler_conf.split_load_value == 0) {
62 "Scheduler load value should be greater than 0");
63 }
64
65 solver.init_required_fields();
66 ctx.init_sched(
67 solver.solver_config.scheduler_conf.split_load_value,
68 solver.solver_config.scheduler_conf.merge_load_value);
69
70 using namespace shamrock::patch;
71
72 PatchScheduler &sched = shambase::get_check_ref(ctx.sched);
73
74 sched.add_root_patch();
75
76 shamlog_debug_ln("Sys", "build local scheduler tables");
79 sched.update_local_load_value([&](shamrock::patch::Patch p) {
80 return sched.patch_data.owned_data.get(p.id_patch).get_obj_cnt();
81 });
82 solver.init_ghost_layout();
83
84 solver.ensure_time_state_edges();
85
87
88 // must be bone after time state edges are ensured (it will connect to it)
89 solver.init_solver_graph();
90}
91
92REGISTER_IDATAEDGESERIALIZABLE(shamrock::solvergraph::IDataEdgeSerializable<f64>);
93REGISTER_IDATAEDGESERIALIZABLE(shamrock::solvergraph::IDataEdgeSerializable<std::vector<f64>>);
94REGISTER_IDATAEDGESERIALIZABLE(shamrock::solvergraph::IDataEdgeSerializable<std::vector<f64_3>>);
95
96template<class Tvec, template<class> class SPHKernel>
97u64 shammodels::sph::Model<Tvec, SPHKernel>::get_total_part_count() {
98 PatchScheduler &sched = shambase::get_check_ref(ctx.sched);
99 return shamalgs::collective::allreduce_sum(sched.get_rank_count());
100}
101
102template<class Tvec, template<class> class SPHKernel>
103f64 shammodels::sph::Model<Tvec, SPHKernel>::total_mass_to_part_mass(f64 totmass) {
104 return totmass / get_total_part_count();
105}
106
107template<class Tvec, template<class> class SPHKernel>
108auto shammodels::sph::Model<Tvec, SPHKernel>::get_closest_part_to(Tvec pos) -> Tvec {
109 StackEntry stack_loc{};
110
111 using namespace shamrock::patch;
112
113 Tvec best_dr = shambase::VectorProperties<Tvec>::get_max();
114 Tscal best_dist2 = shambase::VectorProperties<Tscal>::get_max();
115
116 PatchScheduler &sched = shambase::get_check_ref(ctx.sched);
117
118 sched.for_each_patchdata_nonempty([&](const Patch, PatchDataLayer &pdat) {
119 auto acc = pdat.get_field<Tvec>(0).get_buf().copy_to_stdvec();
120
121 u32 cnt = pdat.get_obj_cnt();
122
123 for (u32 i = 0; i < cnt; i++) {
124 Tvec tmp = acc[i];
125 Tvec dr = tmp - pos;
126 Tscal dist2 = sycl::dot(dr, dr);
127 if (dist2 < best_dist2) {
128 best_dr = dr;
129 best_dist2 = dist2;
130 }
131 }
132 });
133
134 std::vector<Tvec> list_dr{};
135 shamalgs::collective::vector_allgatherv(std::vector<Tvec>{best_dr}, list_dr, MPI_COMM_WORLD);
136
137 // reset distances because if two rank find the same distance the return value won't be the same
138 // this bug took me a whole day to fix, aaaaaaaaaaaaah !!!!!
139 // maybe this should be moved somewhere else to prevent similar issues
140 // TODO (in a year maybe XD )
141 best_dr = shambase::VectorProperties<Tvec>::get_max();
142 best_dist2 = shambase::VectorProperties<Tscal>::get_max();
143
144 for (Tvec tmp : list_dr) {
145 Tvec dr = tmp - pos;
146 Tscal dist2 = sycl::dot(dr, dr);
147 if (dist2 < best_dist2) {
148 best_dr = dr;
149 best_dist2 = dist2;
150 }
151 }
152
153 return pos + best_dr;
154}
155
156template<class Tvec, template<class> class SPHKernel>
157void shammodels::sph::Model<Tvec, SPHKernel>::remap_positions(std::function<Tvec(Tvec)> map) {
158 StackEntry stack_loc{};
159
160 using namespace shamrock::patch;
161
162 PatchScheduler &sched = shambase::get_check_ref(ctx.sched);
163 sched.for_each_patchdata_nonempty([&](const Patch, PatchDataLayer &pdat) {
164 auto &xyz = pdat.get_field<Tvec>(0).get_buf();
165 auto acc = xyz.copy_to_stdvec();
166
167 u32 cnt = pdat.get_obj_cnt();
168
169 for (u32 i = 0; i < cnt; i++) {
170 acc[i] = map(acc[i]);
171 }
172
173 xyz.copy_from_stdvec(acc);
174 });
175
176 modules::ComputeLoadBalanceValue<Tvec, SPHKernel>(ctx, solver.solver_config, solver.storage)
177 .update_load_balancing();
178 sched.scheduler_step(false, false);
179
180 {
181 StackEntry stack_loc{};
183 sched.patch_tree, sched.get_sim_box().get_patch_transform<Tvec>());
185 sptree.attach_buf();
186 reatrib.reatribute_patch_objects(sptree, "xyz");
187 sched.check_patchdata_locality_correctness();
188 }
189
190 modules::ComputeLoadBalanceValue<Tvec, SPHKernel>(ctx, solver.solver_config, solver.storage)
191 .update_load_balancing();
192 sched.scheduler_step(true, true);
193
194 {
195 StackEntry stack_loc{};
197 sched.patch_tree, sched.get_sim_box().get_patch_transform<Tvec>());
198
200 sptree.attach_buf();
201 reatrib.reatribute_patch_objects(sptree, "xyz");
202 sched.check_patchdata_locality_correctness();
203 }
204}
205
206template<class Tvec>
207inline void post_insert_data(PatchScheduler &sched) {
208 StackEntry stack_loc{};
209
210 // logger::raw_ln(sched.dump_status());
211 sched.scheduler_step(false, false);
212
213 /*
214 if(shamcomm::world_rank() == 7){
215 logger::raw_ln(sched.dump_status());
216 }
217 */
218
219 auto [m, M] = sched.get_box_tranform<Tvec>();
220
221 {
222 StackEntry stack_loc{};
224 sched.patch_tree, sched.get_sim_box().get_patch_transform<Tvec>());
226 sptree.attach_buf();
227 reatrib.reatribute_patch_objects(sptree, "xyz");
228 sched.check_patchdata_locality_correctness();
229 }
230
231 sched.scheduler_step(true, true);
232
233 {
234 StackEntry stack_loc{};
236 sched.patch_tree, sched.get_sim_box().get_patch_transform<Tvec>());
237
239 sptree.attach_buf();
240 reatrib.reatribute_patch_objects(sptree, "xyz");
241 sched.check_patchdata_locality_correctness();
242 }
243
244 std::string log = "";
245
246 using namespace shamrock::patch;
247
248 u32 smallest_count = u32_max;
249 u32 largest_count = 0;
250
251 sched.for_each_local_patchdata([&](const Patch &p, PatchDataLayer &pdat) {
252 u32 tmp = pdat.get_obj_cnt();
253 smallest_count = sham::min(tmp, smallest_count);
254 largest_count = sham::max(tmp, largest_count);
255 });
256
257 smallest_count = shamalgs::collective::allreduce_min(smallest_count);
258 largest_count = shamalgs::collective::allreduce_max(largest_count);
259
260 if (shamcomm::world_rank() == 0) {
262 "Model", "current particle counts : min = ", smallest_count, "max = ", largest_count);
263 }
264
265 // sched.for_each_local_patchdata([&](const Patch p, PatchData &pdat) {
266 // log += shambase::format(
267 // "\n patch id={}, N={} particles", p.id_patch, pdat.get_obj_cnt());
268 // });
269 //
270 // std::string log_gathered = "";
271 // shamalgs::collective::gather_str(log, log_gathered);
272 //
273 // if (shamcomm::world_rank() == 0)
274 // logger::info_ln("Model", "current particle counts : ", log_gathered);
275}
276
277template<class Tvec, template<class> class SPHKernel>
278void shammodels::sph::Model<Tvec, SPHKernel>::push_particle(
279 std::vector<Tvec> &part_pos_insert,
280 std::vector<Tscal> &part_hpart_insert,
281 std::vector<Tscal> &part_u_insert) {
282 StackEntry stack_loc{};
283
284 using namespace shamrock::patch;
285
286 PatchScheduler &sched = shambase::get_check_ref(ctx.sched);
287
288 std::string log = "";
289
290 sched.for_each_local_patchdata([&](const Patch &p, PatchDataLayer &pdat) {
291 PatchCoordTransform<Tvec> ptransf = sched.get_sim_box().get_patch_transform<Tvec>();
292
293 shammath::CoordRange<Tvec> patch_coord = ptransf.to_obj_coord(p);
294
295 std::vector<Tvec> vec_acc;
296 std::vector<Tscal> hpart_acc;
297 std::vector<Tscal> u_acc;
298 for (u32 i = 0; i < part_pos_insert.size(); i++) {
299 Tvec r = part_pos_insert[i];
300 Tscal u = part_u_insert[i];
301 if (patch_coord.contain_pos(r)) {
302 vec_acc.push_back(r);
303 hpart_acc.push_back(part_hpart_insert[i]);
304 u_acc.push_back(u);
305 }
306 }
307
308 if (vec_acc.size() == 0) {
309 return;
310 }
311
312 log += shambase::format(
313 "\n rank = {} patch id={}, add N={} particles, coords = {} {}",
315 p.id_patch,
316 vec_acc.size(),
317 patch_coord.lower,
318 patch_coord.upper);
319
320 PatchDataLayer tmp(sched.get_layout_ptr_old());
321 tmp.resize(vec_acc.size());
322 tmp.fields_raz();
323
324 {
325 u32 len = vec_acc.size();
327 = tmp.get_field<Tvec>(sched.pdl_old().get_field_idx<Tvec>("xyz"));
328 sycl::buffer<Tvec> buf(vec_acc.data(), len);
329 f.override(buf, len);
330 }
331
332 {
333 u32 len = vec_acc.size();
335 = tmp.get_field<Tscal>(sched.pdl_old().get_field_idx<Tscal>("hpart"));
336 sycl::buffer<Tscal> buf(hpart_acc.data(), len);
337 f.override(buf, len);
338 }
339
340 {
341 u32 len = u_acc.size();
343 = tmp.get_field<Tscal>(sched.pdl_old().get_field_idx<Tscal>("uint"));
344 sycl::buffer<Tscal> buf(u_acc.data(), len);
345 f.override(buf, len);
346 }
347
348 pdat.insert_elements(tmp);
349
350 sched.check_patchdata_locality_correctness();
351
352 std::string log_gathered = "";
353 shamalgs::collective::gather_str(log, log_gathered);
354
355 if (shamcomm::world_rank() == 0) {
356 logger::info_ln("Model", "Push particles : ", log_gathered);
357 }
358 log = "";
359
360 modules::ComputeLoadBalanceValue<Tvec, SPHKernel>(ctx, solver.solver_config, solver.storage)
361 .update_load_balancing();
362
363 post_insert_data<Tvec>(sched);
364 });
365}
366
367template<class Tvec, template<class> class SPHKernel>
368void shammodels::sph::Model<Tvec, SPHKernel>::push_particle_mhd(
369 std::vector<Tvec> &part_pos_insert,
370 std::vector<Tscal> &part_hpart_insert,
371 std::vector<Tscal> &part_u_insert,
372 std::vector<Tvec> &part_B_on_rho_insert,
373 std::vector<Tscal> &part_psi_on_ch_insert) {
374 StackEntry stack_loc{};
375
376 using namespace shamrock::patch;
377
378 PatchScheduler &sched = shambase::get_check_ref(ctx.sched);
379
380 std::string log = "";
381
382 sched.for_each_local_patchdata([&](const Patch &p, PatchDataLayer &pdat) {
383 PatchCoordTransform<Tvec> ptransf = sched.get_sim_box().get_patch_transform<Tvec>();
384
385 shammath::CoordRange<Tvec> patch_coord = ptransf.to_obj_coord(p);
386
387 std::vector<Tvec> vec_acc;
388 std::vector<Tscal> hpart_acc;
389 std::vector<Tscal> u_acc;
390 std::vector<Tvec> B_on_rho_acc;
391 std::vector<Tscal> psi_on_ch_acc;
392 for (u32 i = 0; i < part_pos_insert.size(); i++) {
393 Tvec r = part_pos_insert[i];
394 Tscal u = part_u_insert[i];
395 if (patch_coord.contain_pos(r)) {
396 vec_acc.push_back(r);
397 hpart_acc.push_back(part_hpart_insert[i]);
398 u_acc.push_back(u);
399 B_on_rho_acc.push_back(part_B_on_rho_insert[i]);
400 psi_on_ch_acc.push_back(part_psi_on_ch_insert[i]);
401 }
402 }
403
404 if (vec_acc.size() == 0) {
405 return;
406 }
407
408 log += shambase::format(
409 "\n rank = {} patch id={}, add N={} particles, coords = {} {}",
411 p.id_patch,
412 vec_acc.size(),
413 patch_coord.lower,
414 patch_coord.upper);
415
416 PatchDataLayer tmp(sched.get_layout_ptr_old());
417 tmp.resize(vec_acc.size());
418 tmp.fields_raz();
419
420 {
421 u32 len = vec_acc.size();
423 = tmp.get_field<Tvec>(sched.pdl_old().get_field_idx<Tvec>("xyz"));
424 sycl::buffer<Tvec> buf(vec_acc.data(), len);
425 f.override(buf, len);
426 }
427
428 {
429 u32 len = vec_acc.size();
431 = tmp.get_field<Tscal>(sched.pdl_old().get_field_idx<Tscal>("hpart"));
432 sycl::buffer<Tscal> buf(hpart_acc.data(), len);
433 f.override(buf, len);
434 }
435
436 {
437 u32 len = u_acc.size();
439 = tmp.get_field<Tscal>(sched.pdl_old().get_field_idx<Tscal>("uint"));
440 sycl::buffer<Tscal> buf(u_acc.data(), len);
441 f.override(buf, len);
442 }
443
444 {
445 u32 len = vec_acc.size();
447 = tmp.get_field<Tvec>(sched.pdl_old().get_field_idx<Tvec>("B/rho"));
448 sycl::buffer<Tvec> buf(B_on_rho_acc.data(), len);
449 f.override(buf, len);
450 }
451
452 {
453 u32 len = vec_acc.size();
455 = tmp.get_field<Tscal>(sched.pdl_old().get_field_idx<Tscal>("psi/ch"));
456 sycl::buffer<Tscal> buf(psi_on_ch_acc.data(), len);
457 f.override(buf, len);
458 }
459
460 pdat.insert_elements(tmp);
461
462 sched.check_patchdata_locality_correctness();
463
464 std::string log_gathered = "";
465 shamalgs::collective::gather_str(log, log_gathered);
466
467 if (shamcomm::world_rank() == 0) {
468 logger::info_ln("Model", "Push particles MHD : ", log_gathered);
469 }
470 log = "";
471
472 modules::ComputeLoadBalanceValue<Tvec, SPHKernel>(ctx, solver.solver_config, solver.storage)
473 .update_load_balancing();
474
475 post_insert_data<Tvec>(sched);
476 });
477}
478
479template<class Tvec, template<class> class SPHKernel>
480void shammodels::sph::Model<Tvec, SPHKernel>::add_cube_hcp_3d(
481 Tscal dr, std::pair<Tvec, Tvec> _box) {
482 shambase::Timer time_setup;
483 time_setup.start();
484
485 StackEntry stack_loc{};
486
488
489 using namespace shamrock::patch;
490
491 PatchScheduler &sched = shambase::get_check_ref(ctx.sched);
492
493 using Lattice = shammath::LatticeHCP<Tvec>;
494 using LatticeIter = typename shammath::LatticeHCP<Tvec>::IteratorDiscontinuous;
495
496 auto [idxs_min, idxs_max] = Lattice::get_box_index_bounds(dr, box.lower, box.upper);
497
498 LatticeIter gen = LatticeIter(dr, idxs_min, idxs_max);
499
500 u64 acc_count = 0;
501
502 std::string log = "";
503 while (!gen.is_done()) {
504
505 // loc maximum count of insert part
506 u64 loc_sum_ins_cnt = 0;
507 // sum_node( loc_sum_ins_cnt )
508 u64 max_loc_sum_ins_cnt = 0;
509
510 do {
511 std::vector<Tvec> to_ins = gen.next_n(sched.crit_patch_split * 2);
512 acc_count += to_ins.size();
513
514 sched.for_each_local_patchdata([&](const Patch &p, PatchDataLayer &pdat) {
515 PatchCoordTransform<Tvec> ptransf = sched.get_sim_box().get_patch_transform<Tvec>();
516
517 shammath::CoordRange<Tvec> patch_coord = ptransf.to_obj_coord(p);
518
519 std::vector<Tvec> vec_acc;
520 for (Tvec r : to_ins) {
521 if (patch_coord.contain_pos(r)) {
522 vec_acc.push_back(r);
523 }
524 }
525
526 // update max insert_count
527 loc_sum_ins_cnt += vec_acc.size();
528
529 if (vec_acc.size() == 0) {
530 return;
531 }
532
533 log += shambase::format(
534 "\n rank = {} patch id={}, add N={} particles, coords = {} {}",
536 p.id_patch,
537 vec_acc.size(),
538 patch_coord.lower,
539 patch_coord.upper);
540
541 // reserve space to avoid allocating during copy
542 pdat.reserve(vec_acc.size());
543
544 PatchDataLayer tmp(sched.get_layout_ptr_old());
545 tmp.resize(vec_acc.size());
546 tmp.fields_raz();
547
548 {
549 u32 len = vec_acc.size();
551 = tmp.get_field<Tvec>(sched.pdl_old().get_field_idx<Tvec>("xyz"));
552 // sycl::buffer<Tvec> buf(vec_acc.data(), len);
553 f.override(vec_acc, len);
554 }
555
556 {
558 = tmp.get_field<Tscal>(sched.pdl_old().get_field_idx<Tscal>("hpart"));
559 f.override(dr);
560 }
561
562 pdat.insert_elements(tmp);
563 });
564
565 max_loc_sum_ins_cnt = shamalgs::collective::allreduce_max(loc_sum_ins_cnt);
566
567 if (shamcomm::world_rank() == 0) {
569 "Model",
570 "--> insertion loop : max loc insert count = ",
571 max_loc_sum_ins_cnt,
572 "sum =",
573 acc_count);
574 }
575 } while (!gen.is_done() && max_loc_sum_ins_cnt < sched.crit_patch_split * 8);
576
577 sched.check_patchdata_locality_correctness();
578
579 // if(logger::details::loglevel >= shamcomm::logs::log_info){
580 // std::string log_gathered = "";
581 // shamalgs::collective::gather_str(log, log_gathered);
582 //
583 // if (shamcomm::world_rank() == 0) {
584 // shamlog_debug_ln("Model", "Push particles : ", log_gathered);
585 // }
586 // }
587 log = "";
588
589 modules::ComputeLoadBalanceValue<Tvec, SPHKernel>(ctx, solver.solver_config, solver.storage)
590 .update_load_balancing();
591 post_insert_data<Tvec>(sched);
592 }
593
594 if (true) {
595 modules::ParticleReordering<Tvec, u32, SPHKernel>(ctx, solver.solver_config, solver.storage)
596 .reorder_particles();
597 }
598
599 time_setup.stop();
600 if (shamcomm::world_rank() == 0) {
601 logger::info_ln("Model", "add_cube_hcp took :", time_setup.elapsed_sec(), "s");
602 }
603}
604
605template<class Tvec, template<class> class SPHKernel>
606void shammodels::sph::Model<Tvec, SPHKernel>::add_cube_hcp_3d_v2(
607 Tscal dr, std::pair<Tvec, Tvec> _box) {
608 shambase::Timer time_setup;
609 time_setup.start();
610 StackEntry stack_loc{};
611
613 using namespace shamrock::patch;
614
615 PatchScheduler &sched = shambase::get_check_ref(ctx.sched);
616
617 using Lattice = shammath::LatticeHCP<Tvec>;
618 using LatticeIter = typename shammath::LatticeHCP<Tvec>::IteratorDiscontinuous;
619
620 auto [idxs_min, idxs_max] = Lattice::get_box_index_bounds(dr, box.lower, box.upper);
621
622 LatticeIter gen = LatticeIter(dr, idxs_min, idxs_max);
623
624 shamrock::DataInserterUtility inserter(sched);
625
626 auto push_current_data = [&](std::vector<Tvec> pos_data) {
627 PatchDataLayer tmp(sched.get_layout_ptr_old());
628 tmp.resize(pos_data.size());
629 tmp.fields_raz();
630
631 {
632 u32 len = pos_data.size();
634 = tmp.get_field<Tvec>(sched.pdl_old().get_field_idx<Tvec>("xyz"));
635 // sycl::buffer<Tvec> buf(pos_data.data(), len);
636 f.override(pos_data, len);
637 }
638
639 {
641 = tmp.get_field<Tscal>(sched.pdl_old().get_field_idx<Tscal>("hpart"));
642 f.override(dr);
643 }
644
645 inserter.push_patch_data<Tvec>(tmp, "xyz", sched.crit_patch_split * 8, [&]() {
646 modules::ComputeLoadBalanceValue<Tvec, SPHKernel>(
647 ctx, solver.solver_config, solver.storage)
648 .update_load_balancing();
649 });
650 pos_data.clear();
651 };
652
653 u32 insert_step = sched.crit_patch_split * 8;
654
655 auto [bmin, bmax] = sched.patch_data.sim_box.get_bounding_box<Tvec>();
656
657 auto has_pdat = [&]() {
658 bool ret = false;
659 sched.for_each_local_patchdata([&](const Patch &p, PatchDataLayer &pdat) {
660 ret = true;
661 });
662 return ret;
663 };
664
665 // Every MPI rank should be synchroneous on gen state
666 while (!gen.is_done()) {
667
668 u64 loc_gen_count = (has_pdat()) ? insert_step : 0;
669
670 auto gen_info = shamalgs::collective::fetch_view(loc_gen_count);
671
672 u64 skip_start = gen_info.head_offset;
673 u64 gen_cnt = loc_gen_count;
674 u64 skip_end = gen_info.total_byte_count - loc_gen_count - gen_info.head_offset;
675
676 shamlog_debug_ln(
677 "Gen",
678 "generate : ",
679 skip_start,
680 gen_cnt,
681 skip_end,
682 "total",
683 skip_start + gen_cnt + skip_end);
684 gen.skip(skip_start);
685 auto tmp = gen.next_n(gen_cnt);
686 gen.skip(skip_end);
687
688 std::vector<Tvec> pos_data;
689 for (Tvec r : tmp) {
690 if (Patch::is_in_patch_converted(r, bmin, bmax)) {
691 pos_data.push_back(r);
692 }
693 }
694
695 push_current_data(pos_data);
696
697 shamlog_debug_ln("Gen", "gen.is_done()", gen.is_done());
698 }
699
700 time_setup.stop();
701 if (shamcomm::world_rank() == 0) {
702 logger::info_ln("Model", "add_cube_hcp took :", time_setup.elapsed_sec(), "s");
703 }
704}
705
706template<class Tvec>
708 public:
709 using Tscal = shambase::VecComponent<Tvec>;
711
712 class DiscIterator {
713 bool done = false;
714 Tvec center;
715 Tscal central_mass;
716 u64 Npart;
717 Tscal r_in;
718 Tscal r_out;
719 Tscal disc_mass;
720 Tscal p;
721 Tscal H_r_in;
722 Tscal q;
723 Tscal G;
724
725 u64 current_index;
726
727 std::mt19937 eng;
728
729 std::function<Tscal(Tscal)> sigma_profile;
730 std::function<Tscal(Tscal)> cs_profile;
731 std::function<Tscal(Tscal)> rot_profile;
732 std::function<Tscal(Tscal)> vel_full_corr;
733
734 public:
735 DiscIterator(
736 Tvec center,
737 Tscal central_mass,
738 u64 Npart,
739 Tscal r_in,
740 Tscal r_out,
741 Tscal disc_mass,
742 Tscal p,
743 Tscal H_r_in,
744 Tscal q,
745 Tscal G,
746 std::mt19937 eng,
747 std::function<Tscal(Tscal)> sigma_profile,
748 std::function<Tscal(Tscal)> cs_profile,
749 std::function<Tscal(Tscal)> rot_profile)
750 : current_index(0), Npart(Npart), center(center), central_mass(central_mass),
751 r_in(r_in), r_out(r_out), disc_mass(disc_mass), p(p), H_r_in(H_r_in), q(q), G(G),
752 eng(eng), sigma_profile(sigma_profile), cs_profile(cs_profile),
753 rot_profile(rot_profile) {
754
755 if (Npart == 0) {
756 done = true;
757 }
758 }
759
760 inline bool is_done() { return done; } // just to make sure the result is not tempered with
761
763
764 constexpr Tscal _2pi = 2 * shambase::constants::pi<Tscal>;
765
766 auto f_func = [&](Tscal r) {
767 return r * sigma_profile(r);
768 };
769
770 Tscal fmax = f_func(r_out);
771
772 auto find_r = [&]() {
773 while (true) {
774 Tscal u2 = shamalgs::primitives::mock_value<Tscal>(eng, 0, fmax);
775 Tscal r = shamalgs::primitives::mock_value<Tscal>(eng, r_in, r_out);
776 if (u2 < f_func(r)) {
777 return r;
778 }
779 }
780 };
781
782 auto theta = shamalgs::primitives::mock_value<Tscal>(eng, 0, _2pi);
783 auto Gauss = shamalgs::random::mock_gaussian<Tscal>(eng);
784 Tscal aspin = 2.;
785
786 Tscal r = find_r();
787
788 Tscal vk = rot_profile(r);
789 Tscal cs = cs_profile(r);
790 Tscal sigma = sigma_profile(r);
791
792 Tscal Omega_Kep = sycl::sqrt(G * central_mass / (r * r * r));
793
794 // Tscal H_r = cs/vk;
795 // Tscal H = H_r * r;
796 Tscal H = sycl::sqrt(2.) * 3. * cs
797 / Omega_Kep; // factor taken from phantom, to fasten thermalizing
798
799 Tscal z = H * Gauss;
800
801 auto pos = sycl::vec<Tscal, 3>{r * sycl::cos(theta), z, r * sycl::sin(theta)};
802
803 auto etheta = sycl::vec<Tscal, 3>{-pos.z(), 0, pos.x()};
804 etheta /= sycl::length(etheta);
805
806 auto vel = vk * etheta;
807
808 // Tscal rho = (sigma / (H * shambase::constants::pi2_sqrt<Tscal>))*
809 // sycl::exp(- z*z / (2*H*H));
810
811 Tscal fs = 1. - sycl::sqrt(r_in / r);
812 Tscal rho = (sigma * fs) * sycl::exp(-z * z / (2 * H * H));
813
814 Out out{pos, vel, cs, rho};
815
816 // increase counter + check if finished
817 current_index++;
818 if (current_index == Npart) {
819 done = true;
820 }
821
822 return out;
823 }
824
825 inline std::vector<Out> next_n(u32 nmax) {
826 std::vector<Out> ret{};
827 for (u32 i = 0; i < nmax; i++) {
828 if (done) {
829 break;
830 }
831
832 ret.push_back(next());
833 }
834 return ret;
835 }
836 };
837};
838
839template<class Tvec, template<class> class SPHKernel>
840void shammodels::sph::Model<Tvec, SPHKernel>::add_big_disc_3d(
841 Tvec center,
842 Tscal central_mass,
843 u32 Npart,
844 Tscal r_in,
845 Tscal r_out,
846 Tscal disc_mass,
847 Tscal p,
848 Tscal H_r_in,
849 Tscal q,
850 std::mt19937 eng) {
851
852 Tscal eos_gamma;
853 using Config = SolverConfig;
854 using SolverConfigEOS = typename Config::EOSConfig;
855 using SolverEOS_Adiabatic = typename SolverConfigEOS::Adiabatic;
856 if (SolverEOS_Adiabatic *eos_config
857 = std::get_if<SolverEOS_Adiabatic>(&solver.solver_config.eos_config.config)) {
858
859 eos_gamma = eos_config->gamma;
860
861 } else {
862 // dirty hack for disc setup in locally isothermal
863 eos_gamma = 2;
864 // shambase::throw_unimplemented();
865 }
866
867 auto sigma_profile = [=](Tscal r) {
868 // we setup with an adimensional mass since it is monte carlo
869 constexpr Tscal sigma_0 = 1;
870 return sigma_0 * sycl::pow(r / r_in, -p);
871 };
872
873 auto cs_law = [=](Tscal r) {
874 return sycl::pow(r / r_in, -q);
875 };
876
877 auto kep_profile = [&](Tscal r) {
878 Tscal G = solver.solver_config.get_constant_G();
879 return sycl::sqrt(G * central_mass / r);
880 };
881
882 auto rot_profile = [&](Tscal r) -> Tscal {
883 // carefull: needs r in cylindrical
884 Tscal G = solver.solver_config.get_constant_G();
885 Tscal c = solver.solver_config.get_constant_c();
886 Tscal aspin = 2.;
887 Tscal term = G * central_mass / r;
888 Tscal term_fs = 1. - sycl::sqrt(r_in / r);
889 Tscal term_pr
890 = -sycl::pown(cs_law(r), 2) * (1.5 + p + q); // NO CORRECTION from fs term, bad response
891 Tscal term_bh = 0.; //- (2. * aspin / sycl::pow(c, 3)) * sycl::pow(G * central_mass / r, 2);
892 Tscal det = sycl::pown(term_bh, 2) + 4. * (term + term_pr);
893 Tscal Rg = G * central_mass / sycl::pown(c, 2);
894 Tscal vkep = sqrt(G * central_mass / r);
895
896 Tscal vphi = 0.5 * (term_bh + sycl::sqrt(det));
897
898 return vphi;
899 };
900
901 auto cs_profile = [&](Tscal r) {
902 Tscal cs_in = (H_r_in * r_in / r) * kep_profile(r_in); // H_r_in*rot_profile(r_in);
903 return cs_law(r) * cs_in;
904 };
905
906 auto get_hfact = []() -> Tscal {
907 return Kernel::hfactd;
908 };
909
910 auto int_rho_h = [&](Tscal h) -> Tscal {
911 return shamrock::sph::rho_h(solver.solver_config.gpart_mass, h, Kernel::hfactd);
912 };
913
914 Tscal part_mass = disc_mass / Npart;
915
916 shambase::Timer time_setup;
917 time_setup.start();
918
919 StackEntry stack_loc{};
920
921 using namespace shamrock::patch;
922
923 PatchScheduler &sched = shambase::get_check_ref(ctx.sched);
924
926 using DIter = typename BigDiscUtils<Tvec>::DiscIterator;
927
928 Tscal G = solver.solver_config.get_constant_G();
929 DIter gen = DIter(
930 center,
931 central_mass,
932 Npart,
933 r_in,
934 r_out,
935 disc_mass,
936 p,
937 H_r_in,
938 q,
939 G,
940 eng,
941 sigma_profile,
942 cs_profile,
943 rot_profile);
944
945 u64 acc_count = 0;
946
947 std::string log = "";
948 while (!gen.is_done()) {
949
950 // loc maximum count of insert part
951 u64 loc_sum_ins_cnt = 0;
952 // sum_node( loc_sum_ins_cnt )
953 u64 max_loc_sum_ins_cnt = 0;
954
955 do {
956 std::vector<Out> to_ins = gen.next_n(sched.crit_patch_split * 2);
957 acc_count += to_ins.size();
958
959 sched.for_each_local_patchdata([&](const Patch &p, PatchDataLayer &pdat) {
960 PatchCoordTransform<Tvec> ptransf = sched.get_sim_box().get_patch_transform<Tvec>();
961
962 shammath::CoordRange<Tvec> patch_coord = ptransf.to_obj_coord(p);
963
964 std::vector<Out> part_list;
965 for (Out r : to_ins) {
966 if (patch_coord.contain_pos(r.pos)) {
967 // add all part to insert in a vector
968 part_list.push_back(r);
969 }
970 }
971
972 // update max insert_count
973 loc_sum_ins_cnt += part_list.size();
974
975 if (part_list.size() == 0) {
976 return;
977 }
978
979 log += shambase::format(
980 "\n rank = {} patch id={}, add N={} particles, coords = {} {}",
982 p.id_patch,
983 part_list.size(),
984 patch_coord.lower,
985 patch_coord.upper);
986
987 // extract the pos from part_list
988 std::vector<Tvec> vec_pos;
989 std::vector<Tvec> vec_vel;
990 std::vector<Tscal> vec_u;
991 std::vector<Tscal> vec_h;
992 std::vector<Tscal> vec_cs;
993
994 for (Out o : part_list) {
995 vec_pos.push_back(o.pos);
996 vec_vel.push_back(o.velocity);
997 vec_u.push_back(o.cs * o.cs / (/*solver.eos_gamma * */ (eos_gamma - 1)));
998 vec_h.push_back(shamrock::sph::h_rho(part_mass, o.rho * 0.1, Kernel::hfactd));
999 vec_cs.push_back(o.cs);
1000 }
1001
1002 // reserve space to avoid allocating during copy
1003 pdat.reserve(vec_pos.size());
1004
1005 PatchDataLayer tmp(sched.get_layout_ptr_old());
1006 tmp.resize(vec_pos.size());
1007 tmp.fields_raz();
1008
1009 {
1010 u32 len = vec_pos.size();
1012 = tmp.get_field<Tvec>(sched.pdl_old().get_field_idx<Tvec>("xyz"));
1013 sycl::buffer<Tvec> buf(vec_pos.data(), len);
1014 f.override(buf, len);
1015 }
1016
1017 {
1018 u32 len = vec_pos.size();
1020 = tmp.get_field<Tscal>(sched.pdl_old().get_field_idx<Tscal>("hpart"));
1021 sycl::buffer<Tscal> buf(vec_h.data(), len);
1022 f.override(buf, len);
1023 }
1024
1025 {
1026 u32 len = vec_pos.size();
1028 = tmp.get_field<Tscal>(sched.pdl_old().get_field_idx<Tscal>("uint"));
1029 sycl::buffer<Tscal> buf(vec_u.data(), len);
1030 f.override(buf, len);
1031 }
1032
1033 if (solver.solver_config.is_eos_locally_isothermal()) {
1034 u32 len = vec_pos.size();
1036 = tmp.get_field<Tscal>(sched.pdl_old().get_field_idx<Tscal>("soundspeed"));
1037 sycl::buffer<Tscal> buf(vec_cs.data(), len);
1038 f.override(buf, len);
1039 }
1040
1041 {
1042 u32 len = vec_pos.size();
1044 = tmp.get_field<Tvec>(sched.pdl_old().get_field_idx<Tvec>("vxyz"));
1045 sycl::buffer<Tvec> buf(vec_vel.data(), len);
1046 f.override(buf, len);
1047 }
1048
1049 pdat.insert_elements(tmp);
1050 });
1051
1052 max_loc_sum_ins_cnt = shamalgs::collective::allreduce_max(loc_sum_ins_cnt);
1053
1054 if (shamcomm::world_rank() == 0) {
1056 "Model",
1057 "--> insertion loop : max loc insert count = ",
1058 max_loc_sum_ins_cnt,
1059 "sum =",
1060 acc_count);
1061 }
1062 } while (!gen.is_done() && max_loc_sum_ins_cnt < sched.crit_patch_split * 8);
1063
1064 sched.check_patchdata_locality_correctness();
1065
1066 // if(logger::details::loglevel >= shamcomm::logs::log_info){
1067 // std::string log_gathered = "";
1068 // shamalgs::collective::gather_str(log, log_gathered);
1069 //
1070 // if (shamcomm::world_rank() == 0) {
1071 // shamlog_debug_ln("Model", "Push particles : ", log_gathered);
1072 // }
1073 // }
1074 log = "";
1075
1076 modules::ComputeLoadBalanceValue<Tvec, SPHKernel>(ctx, solver.solver_config, solver.storage)
1077 .update_load_balancing();
1078 post_insert_data<Tvec>(sched);
1079 }
1080
1081 if (true) {
1082 modules::ParticleReordering<Tvec, u32, SPHKernel>(ctx, solver.solver_config, solver.storage)
1083 .reorder_particles();
1084 }
1085
1086 time_setup.stop();
1087 if (shamcomm::world_rank() == 0) {
1088 logger::info_ln("Model", "add_big_disc took :", time_setup.elapsed_sec(), "s");
1089 }
1090}
1091
1092template<class Tvec, template<class> class SPHKernel>
1093void shammodels::sph::Model<Tvec, SPHKernel>::add_cube_fcc_3d(
1094 Tscal dr, std::pair<Tvec, Tvec> _box) {
1095 StackEntry stack_loc{};
1096
1097 shammath::CoordRange<Tvec> box = _box;
1098
1099 using namespace shamrock::patch;
1100
1101 PatchScheduler &sched = shambase::get_check_ref(ctx.sched);
1102
1103 std::string log = "";
1104
1105 auto make_sliced = [&]() {
1106 std::vector<Tvec> vec_lst;
1107 generic::setup::generators::add_particles_fcc(
1108 dr,
1109 {box.lower, box.upper},
1110 [&](Tvec r) {
1111 return box.contain_pos(r);
1112 },
1113 [&](Tvec r, Tscal h) {
1114 vec_lst.push_back(r);
1115 });
1116
1117 std::vector<std::vector<Tvec>> sliced_buf;
1118
1119 u32 sz_buf = sched.crit_patch_split * 4;
1120
1121 std::vector<Tvec> cur_buf;
1122 for (u32 i = 0; i < vec_lst.size(); i++) {
1123 cur_buf.push_back(vec_lst[i]);
1124
1125 if (cur_buf.size() > sz_buf) {
1126 sliced_buf.push_back(std::exchange(cur_buf, std::vector<Tvec>{}));
1127 }
1128 }
1129
1130 if (cur_buf.size() > 0) {
1131 sliced_buf.push_back(std::exchange(cur_buf, std::vector<Tvec>{}));
1132 }
1133
1134 return sliced_buf;
1135 };
1136
1137 std::vector<std::vector<Tvec>> sliced_buf = make_sliced();
1138
1139 for (std::vector<Tvec> to_ins : sliced_buf) {
1140
1141 sched.for_each_local_patchdata([&](const Patch &p, PatchDataLayer &pdat) {
1142 PatchCoordTransform<Tvec> ptransf = sched.get_sim_box().get_patch_transform<Tvec>();
1143
1144 shammath::CoordRange<Tvec> patch_coord = ptransf.to_obj_coord(p);
1145
1146 std::vector<Tvec> vec_acc;
1147 for (Tvec r : to_ins) {
1148 if (patch_coord.contain_pos(r)) {
1149 vec_acc.push_back(r);
1150 }
1151 }
1152
1153 if (vec_acc.size() == 0) {
1154 return;
1155 }
1156
1157 log += shambase::format(
1158 "\n rank = {} patch id={}, add N={} particles, coords = {} {}",
1160 p.id_patch,
1161 vec_acc.size(),
1162 patch_coord.lower,
1163 patch_coord.upper);
1164
1165 PatchDataLayer tmp(sched.get_layout_ptr_old());
1166 tmp.resize(vec_acc.size());
1167 tmp.fields_raz();
1168
1169 {
1170 u32 len = vec_acc.size();
1172 = tmp.get_field<Tvec>(sched.pdl_old().get_field_idx<Tvec>("xyz"));
1173 sycl::buffer<Tvec> buf(vec_acc.data(), len);
1174 f.override(buf, len);
1175 }
1176
1177 {
1179 = tmp.get_field<Tscal>(sched.pdl_old().get_field_idx<Tscal>("hpart"));
1180 f.override(dr);
1181 }
1182
1183 pdat.insert_elements(tmp);
1184 });
1185
1186 sched.check_patchdata_locality_correctness();
1187
1188 std::string log_gathered = "";
1189 shamalgs::collective::gather_str(log, log_gathered);
1190
1191 if (shamcomm::world_rank() == 0) {
1192 logger::info_ln("Model", "Push particles : ", log_gathered);
1193 }
1194 log = "";
1195
1196 modules::ComputeLoadBalanceValue<Tvec, SPHKernel>(ctx, solver.solver_config, solver.storage)
1197 .update_load_balancing();
1198 post_insert_data<Tvec>(sched);
1199 }
1200}
1201
1202template<class Tvec, template<class> class SPHKernel>
1203auto shammodels::sph::Model<Tvec, SPHKernel>::gen_config_from_phantom_dump(
1204 PhantomDump &phdump, bool bypass_error) -> SolverConfig {
1205 StackEntry stack_loc{};
1206 SolverConfig conf{};
1207
1208 auto massoftype = phdump.read_header_floats<Tscal>("massoftype");
1209
1210 conf.gpart_mass = massoftype[0];
1211 conf.cfl_config.cfl_cour = phdump.read_header_float<Tscal>("C_cour");
1212 conf.cfl_config.cfl_force = phdump.read_header_float<Tscal>("C_force");
1213
1214 conf.eos_config = get_shamrock_eosconfig<Tvec>(phdump, bypass_error);
1215 conf.artif_viscosity = get_shamrock_avconfig<Tvec>(phdump);
1216
1217 conf.set_units(get_shamrock_units<Tscal>(phdump));
1218
1219 conf.boundary_config = get_shamrock_boundary_config<Tvec>(phdump);
1220
1221 return conf;
1222}
1223
1224template<class Tvec, template<class> class SPHKernel>
1225void shammodels::sph::Model<Tvec, SPHKernel>::init_from_phantom_dump(
1226 PhantomDump &phdump, Tscal hpart_fact_load) {
1227 StackEntry stack_loc{};
1228
1229 bool has_coord_in_header = true;
1230
1231 Tscal xmin, xmax, ymin, ymax, zmin, zmax;
1232 has_coord_in_header = phdump.has_header_entry("xmin");
1233
1234 std::string log = "";
1235
1236 std::vector<Tvec> xyz, vxyz;
1237 std::vector<Tscal> h, u, alpha;
1238
1239 {
1240 std::vector<Tscal> x, y, z, vx, vy, vz;
1241
1242 phdump.blocks[0].fill_vec("x", x);
1243 phdump.blocks[0].fill_vec("y", y);
1244 phdump.blocks[0].fill_vec("z", z);
1245
1246 if (has_coord_in_header) {
1247 xmin = phdump.read_header_float<f64>("xmin");
1248 xmax = phdump.read_header_float<f64>("xmax");
1249 ymin = phdump.read_header_float<f64>("ymin");
1250 ymax = phdump.read_header_float<f64>("ymax");
1251 zmin = phdump.read_header_float<f64>("zmin");
1252 zmax = phdump.read_header_float<f64>("zmax");
1253
1254 resize_simulation_box({{xmin, ymin, zmin}, {xmax, ymax, zmax}});
1255 } else {
1256 Tscal box_tolerance = 1.2;
1257
1258 xmin = *std::min_element(x.begin(), x.end());
1259 xmax = *std::max_element(x.begin(), x.end());
1260 ymin = *std::min_element(y.begin(), y.end());
1261 ymax = *std::max_element(y.begin(), y.end());
1262 zmin = *std::min_element(z.begin(), z.end());
1263 zmax = *std::max_element(z.begin(), z.end());
1264
1265 Tvec bm = {xmin, ymin, zmin};
1266 Tvec bM = {xmax, ymax, zmax};
1267
1268 Tvec center = (bm + bM) * 0.5;
1269
1270 Tvec d = (bM - bm) * 0.5;
1271
1272 // expand the box
1273 d *= box_tolerance;
1274
1275 resize_simulation_box({center - d, center + d});
1276 }
1277
1278 phdump.blocks[0].fill_vec("h", h);
1279
1280 phdump.blocks[0].fill_vec("vx", vx);
1281 phdump.blocks[0].fill_vec("vy", vy);
1282 phdump.blocks[0].fill_vec("vz", vz);
1283
1284 phdump.blocks[0].fill_vec("u", u);
1285 phdump.blocks[0].fill_vec("alpha", alpha);
1286
1287 for (u32 i = 0; i < x.size(); i++) {
1288 xyz.push_back({x[i], y[i], z[i]});
1289 }
1290 for (u32 i = 0; i < vx.size(); i++) {
1291 vxyz.push_back({vx[i], vy[i], vz[i]});
1292 }
1293 }
1294
1295 // Load time infos
1296 f64 time_phdump = phdump.read_header_float<f64>("time");
1297 solver.set_time(time_phdump);
1298
1299 using namespace shamrock::patch;
1300
1301 PatchScheduler &sched = shambase::get_check_ref(ctx.sched);
1302
1303 u32 sz_buf = sched.crit_patch_split * 4;
1304
1305 u32 Ntot = xyz.size();
1306
1307 std::vector<u64> insert_ranges;
1308 insert_ranges.push_back(0);
1309 for (u64 i = sz_buf; i < Ntot; i += sz_buf) {
1310 insert_ranges.push_back(i);
1311 }
1312 insert_ranges.push_back(Ntot);
1313
1314 for (u64 krange = 0; krange < insert_ranges.size() - 1; krange++) {
1315 u64 start_id = insert_ranges[krange];
1316 u64 end_id = insert_ranges[krange + 1];
1317
1318 u64 Nloc = end_id - start_id;
1319
1320 sched.for_each_local_patchdata([&](const Patch &p, PatchDataLayer &pdat) {
1321 PatchCoordTransform<Tvec> ptransf = sched.get_sim_box().get_patch_transform<Tvec>();
1322
1323 shammath::CoordRange<Tvec> patch_coord = ptransf.to_obj_coord(p);
1324
1325 std::vector<u64> sel_index;
1326 for (u64 i = start_id; i < end_id; i++) {
1327 Tvec r = xyz[i];
1328 Tscal h_ = h[i];
1329 if (patch_coord.contain_pos(r) && (h_ >= 0)) {
1330 sel_index.push_back(i);
1331 }
1332 }
1333
1334 if (sel_index.size() == 0) {
1335 return;
1336 }
1337
1338 log += shambase::format(
1339 "\n rank = {} patch id={}, add N={} particles, coords = {} {}",
1341 p.id_patch,
1342 sel_index.size(),
1343 patch_coord.lower,
1344 patch_coord.upper);
1345
1346 std::vector<Tvec> ins_xyz, ins_vxyz;
1347 std::vector<Tscal> ins_h, ins_u, ins_alpha;
1348 for (u64 i : sel_index) {
1349 ins_xyz.push_back(xyz[i]);
1350 }
1351 for (u64 i : sel_index) {
1352 ins_vxyz.push_back(vxyz[i]);
1353 }
1354 for (u64 i : sel_index) {
1355 ins_h.push_back(h[i] * hpart_fact_load);
1356 }
1357 if (u.size() > 0) {
1358 for (u64 i : sel_index) {
1359 ins_u.push_back(u[i]);
1360 }
1361 }
1362 if (alpha.size() > 0) {
1363 for (u64 i : sel_index) {
1364 ins_alpha.push_back(alpha[i]);
1365 }
1366 }
1367
1368 PatchDataLayer ptmp(sched.get_layout_ptr_old());
1369 ptmp.resize(sel_index.size());
1370 ptmp.fields_raz();
1371
1372 ptmp.override_patch_field("xyz", ins_xyz);
1373 ptmp.override_patch_field("vxyz", ins_vxyz);
1374 ptmp.override_patch_field("hpart", ins_h);
1375
1376 if (ins_alpha.size() > 0) {
1377 ptmp.override_patch_field("alpha_AV", ins_alpha);
1378 }
1379
1380 if (ins_u.size() > 0) {
1381 ptmp.override_patch_field("uint", ins_u);
1382 }
1383
1384 pdat.insert_elements(ptmp);
1385 });
1386
1387 sched.check_patchdata_locality_correctness();
1388
1389 std::string log_gathered = "";
1390 shamalgs::collective::gather_str(log, log_gathered);
1391
1392 if (shamcomm::world_rank() == 0) {
1393 logger::info_ln("Model", "Push particles : ", log_gathered);
1394 }
1395 log = "";
1396
1397 modules::ComputeLoadBalanceValue<Tvec, SPHKernel>(ctx, solver.solver_config, solver.storage)
1398 .update_load_balancing();
1399
1400 post_insert_data<Tvec>(sched);
1401
1402 // add sinks
1403
1404 PhantomDumpBlock &sink_block = phdump.blocks[1];
1405 {
1406 std::vector<Tscal> xsink, ysink, zsink;
1407 std::vector<Tscal> vxsink, vysink, vzsink;
1408 std::vector<Tscal> mass;
1409 std::vector<Tscal> Racc;
1410
1411 sink_block.fill_vec("x", xsink);
1412 sink_block.fill_vec("y", ysink);
1413 sink_block.fill_vec("z", zsink);
1414 sink_block.fill_vec("vx", vxsink);
1415 sink_block.fill_vec("vy", vysink);
1416 sink_block.fill_vec("vz", vzsink);
1417 sink_block.fill_vec("m", mass);
1418 sink_block.fill_vec("h", Racc);
1419
1420 for (u32 i = 0; i < xsink.size(); i++) {
1421 add_sink(
1422 mass[i],
1423 {xsink[i], ysink[i], zsink[i]},
1424 {vxsink[i], vysink[i], vzsink[i]},
1425 Racc[i]);
1426 }
1427 }
1428 }
1429}
1430
1431template<class Tvec, template<class> class SPHKernel>
1432void shammodels::sph::Model<Tvec, SPHKernel>::add_pdat_to_phantom_block(
1433 PhantomDumpBlock &block, shamrock::patch::PatchDataLayer &pdat) {
1434
1435 std::vector<Tvec> xyz = pdat.fetch_data<Tvec>("xyz");
1436
1437 u64 xid = block.get_ref_fort_real("x");
1438 u64 yid = block.get_ref_fort_real("y");
1439 u64 zid = block.get_ref_fort_real("z");
1440
1441 for (auto vec : xyz) {
1442 block.blocks_fort_real[xid].vals.push_back(vec.x());
1443 block.blocks_fort_real[yid].vals.push_back(vec.y());
1444 block.blocks_fort_real[zid].vals.push_back(vec.z());
1445 }
1446
1447 std::vector<Tscal> h = pdat.fetch_data<Tscal>("hpart");
1448 u64 hid = block.get_ref_f32("h");
1449 for (auto h_ : h) {
1450 block.blocks_f32[hid].vals.push_back(h_);
1451 }
1452
1453 if (solver.solver_config.has_field_alphaAV()) {
1454 std::vector<Tscal> alpha = pdat.fetch_data<Tscal>("alpha_AV");
1455 u64 aid = block.get_ref_f32("alpha");
1456 for (auto alp_ : alpha) {
1457 block.blocks_f32[aid].vals.push_back(alp_);
1458 }
1459 }
1460
1461 if (solver.solver_config.has_field_divv()) {
1462 std::vector<Tscal> vecdivv = pdat.fetch_data<Tscal>("divv");
1463 u64 divvid = block.get_ref_f32("divv");
1464 for (auto d_ : vecdivv) {
1465 block.blocks_f32[divvid].vals.push_back(d_);
1466 }
1467 }
1468
1469 std::vector<Tvec> vxyz = pdat.fetch_data<Tvec>("vxyz");
1470
1471 u64 vxid = block.get_ref_fort_real("vx");
1472 u64 vyid = block.get_ref_fort_real("vy");
1473 u64 vzid = block.get_ref_fort_real("vz");
1474
1475 for (auto vec : vxyz) {
1476 block.blocks_fort_real[vxid].vals.push_back(vec.x());
1477 block.blocks_fort_real[vyid].vals.push_back(vec.y());
1478 block.blocks_fort_real[vzid].vals.push_back(vec.z());
1479 }
1480
1481 std::vector<Tscal> u = pdat.fetch_data<Tscal>("uint");
1482 u64 uid = block.get_ref_fort_real("u");
1483 for (auto u_ : u) {
1484 block.blocks_fort_real[uid].vals.push_back(u_);
1485 }
1486
1487 block.tot_count = block.blocks_fort_real[xid].vals.size();
1488}
1489
1490template<class Tvec, template<class> class SPHKernel>
1491shammodels::sph::PhantomDump shammodels::sph::Model<Tvec, SPHKernel>::make_phantom_dump() {
1492 StackEntry stack_loc{};
1493
1494 PhantomDump dump;
1495
1496 bool bypass_error_check = false;
1497
1498 auto get_sink_count = [&]() -> int {
1499 return int(get_sink_pos<Tvec>(shambase::get_check_ref(ctx.sched).synchronized_data).size());
1500 };
1501
1502 dump.override_magic_number();
1503 dump.iversion = 1;
1504 dump.fileid = shambase::format("{:100s}", "FT:Phantom Shamrock writer");
1505
1506 u32 Ntot = get_total_part_count();
1507 dump.table_header_fort_int.add("nparttot", Ntot);
1508 dump.table_header_fort_int.add("ntypes", 8);
1509 dump.table_header_fort_int.add("npartoftype", Ntot);
1510 dump.table_header_fort_int.add("npartoftype", 0);
1511 dump.table_header_fort_int.add("npartoftype", 0);
1512 dump.table_header_fort_int.add("npartoftype", 0);
1513 dump.table_header_fort_int.add("npartoftype", 0);
1514 dump.table_header_fort_int.add("npartoftype", 0);
1515 dump.table_header_fort_int.add("npartoftype", 0);
1516 dump.table_header_fort_int.add("npartoftype", 0);
1517
1518 dump.table_header_i64.add("nparttot", Ntot);
1519 dump.table_header_i64.add("ntypes", 8);
1520 dump.table_header_i64.add("npartoftype", Ntot);
1521 dump.table_header_i64.add("npartoftype", 0);
1522 dump.table_header_i64.add("npartoftype", 0);
1523 dump.table_header_i64.add("npartoftype", 0);
1524 dump.table_header_i64.add("npartoftype", 0);
1525 dump.table_header_i64.add("npartoftype", 0);
1526 dump.table_header_i64.add("npartoftype", 0);
1527 dump.table_header_i64.add("npartoftype", 0);
1528
1529 dump.table_header_fort_int.add("nblocks", 1);
1530 dump.table_header_fort_int.add("nptmass", get_sink_count());
1531 dump.table_header_fort_int.add("ndustlarge", 0);
1532 dump.table_header_fort_int.add("ndustsmall", 0);
1533 dump.table_header_fort_int.add("idust", 7);
1534 dump.table_header_fort_int.add("idtmax_n", 1);
1535 dump.table_header_fort_int.add("idtmax_frac", 0);
1536 dump.table_header_fort_int.add("idumpfile", 0);
1537 dump.table_header_fort_int.add("majorv", 2023);
1538 dump.table_header_fort_int.add("minorv", 0);
1539 dump.table_header_fort_int.add("microv", 0);
1540 dump.table_header_fort_int.add("isink", 0);
1541
1542 dump.table_header_i32.add("iexternalforce", 0);
1543
1544 write_shamrock_eos_in_phantom_dump(solver.solver_config.eos_config, dump, bypass_error_check);
1545
1546 dump.table_header_fort_real.add("time", solver.get_time());
1547 dump.table_header_fort_real.add("dtmax", solver.get_dt_sph());
1548
1549 dump.table_header_fort_real.add("rhozero", 0);
1550 dump.table_header_fort_real.add("hfact", Kernel::hfactd);
1551 dump.table_header_fort_real.add("tolh", 0.0001);
1552 dump.table_header_fort_real.add("C_cour", solver.solver_config.cfl_config.cfl_cour);
1553 dump.table_header_fort_real.add("C_force", solver.solver_config.cfl_config.cfl_force);
1554 dump.table_header_fort_real.add("alpha", 0);
1555 dump.table_header_fort_real.add("alphau", 1);
1556 dump.table_header_fort_real.add("alphaB", 1);
1557
1558 dump.table_header_fort_real.add("massoftype", solver.solver_config.gpart_mass);
1559 dump.table_header_fort_real.add("massoftype", 0);
1560 dump.table_header_fort_real.add("massoftype", 0);
1561 dump.table_header_fort_real.add("massoftype", 0);
1562 dump.table_header_fort_real.add("massoftype", 0);
1563 dump.table_header_fort_real.add("massoftype", 0);
1564 dump.table_header_fort_real.add("massoftype", 0);
1565 dump.table_header_fort_real.add("massoftype", 0);
1566
1567 dump.table_header_fort_real.add("Bextx", 0);
1568 dump.table_header_fort_real.add("Bexty", 0);
1569 dump.table_header_fort_real.add("Bextz", 0);
1570 dump.table_header_fort_real.add("dum", 0);
1571
1572 PatchScheduler &sched = shambase::get_check_ref(solver.context.sched);
1573
1574 auto box_size = sched.get_box_volume<Tvec>();
1575
1576 write_shamrock_boundaries_in_phantom_dump(
1577 solver.solver_config.boundary_config, box_size, dump, bypass_error_check);
1578
1579 dump.table_header_fort_real.add("get_conserv", -1);
1580 dump.table_header_fort_real.add("etot_in", 0.59762);
1581 dump.table_header_fort_real.add("angtot_in", 0.0189694);
1582 dump.table_header_fort_real.add("totmom_in", 0.0306284);
1583
1584 write_shamrock_units_in_phantom_dump(solver.solver_config.unit_sys, dump, bypass_error_check);
1585
1586 PhantomDumpBlock block_part;
1587
1588 {
1589 NamedStackEntry stack_loc{"gather data"};
1590 std::vector<std::unique_ptr<shamrock::patch::PatchDataLayer>> gathered
1591 = ctx.allgather_data();
1592
1593 for (auto &dat : gathered) {
1594 add_pdat_to_phantom_block(block_part, shambase::get_check_ref(dat));
1595 }
1596 }
1597
1598 dump.blocks.push_back(std::move(block_part));
1599
1600 {
1601 auto &sync = shambase::get_check_ref(ctx.sched).synchronized_data;
1602 auto edges = get_sink_edges<Tvec>(sync);
1603 if (edges.has_sinks()) {
1604 auto sinks = to_sink_particles(edges);
1605 // add sinks to block 1
1606 PhantomDumpBlock sink_block;
1607
1608 u64 xid = sink_block.get_ref_fort_real("x");
1609 u64 yid = sink_block.get_ref_fort_real("y");
1610 u64 zid = sink_block.get_ref_fort_real("z");
1611 u64 mid = sink_block.get_ref_fort_real("m");
1612 u64 hid = sink_block.get_ref_fort_real("h");
1613 u64 vxid = sink_block.get_ref_fort_real("vx");
1614 u64 vyid = sink_block.get_ref_fort_real("vy");
1615 u64 vzid = sink_block.get_ref_fort_real("vz");
1616
1617 for (SinkParticle<Tvec> s : sinks) {
1618 sink_block.blocks_fort_real[xid].vals.push_back(s.pos.x());
1619 sink_block.blocks_fort_real[yid].vals.push_back(s.pos.y());
1620 sink_block.blocks_fort_real[zid].vals.push_back(s.pos.z());
1621 sink_block.blocks_fort_real[mid].vals.push_back(s.mass);
1622 sink_block.blocks_fort_real[hid].vals.push_back(s.accretion_radius);
1623 sink_block.blocks_fort_real[vxid].vals.push_back(s.velocity.x());
1624 sink_block.blocks_fort_real[vyid].vals.push_back(s.velocity.y());
1625 sink_block.blocks_fort_real[vzid].vals.push_back(s.velocity.z());
1626 }
1627
1628 sink_block.tot_count = sinks.size();
1629
1630 dump.blocks.push_back(std::move(sink_block));
1631 }
1632 }
1633
1634 return dump;
1635}
1636
1637using namespace shammath;
1638
1642
constexpr const char * vxyz
3-velocity field
constexpr const char * xyz
Position field (3D coordinates).
Header file describing a Node Instance.
MPI scheduler.
double f64
Alias for double.
std::uint32_t u32
32 bit unsigned integer
std::uint64_t u64
64 bit unsigned integer
The MPI scheduler.
SchedulerPatchData patch_data
handle the data of the patches of the scheduler
u64 crit_patch_split
splitting limit (if load value > crit_patch_split => patch split)
PatchTree patch_tree
handle the tree structure of the patches
void scheduler_step(bool do_split_merge, bool do_load_balancing)
scheduler step
SynchronizedData synchronized_data
data that is synchroneous across all ranks
SchedulerPatchList patch_list
handle the list of the patches of the scheduler
std::unordered_set< u64 > owned_patch_id
(owned_patch_id = patch_list.build_local())
void add_root_patch()
add patch to the scheduler
std::unordered_set< u64 > build_local()
select owned patches owned by the node to rebuild local
void build_local_idx_map()
recompute id_patch_to_local_idx
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
Iterator utility to generate the lattice.
utility for generating HCP crystal lattices
Vector class based on std::array storage and mdspan.
Definition matrix.hpp:98
The shamrock SPH model.
Definition Model.hpp:56
void init()
Initialise the model and all the related data structures (patch scheduler in particular).
Definition Model.cpp:58
Class to insert data in the PatchScheduler.
Utility class used to move the objects between patches.
PatchDataLayer container class, the layout is described in patchdata_layout.
std::vector< T > fetch_data(std::string key)
Fetch data of a patchdata field into a std::vector.
std::tuple< T, T > get_bounding_box() const
Get the stored bounding box of the domain.
Definition SimBox.hpp:247
PatchCoordTransform< T > get_patch_transform() const
Get a PatchCoordTransform object that describes the conversion between patch coordinates and domain c...
Definition SimBox.hpp:285
shamrock::patch::SimulationBoxInfo sim_box
simulation box geometry info
shambase::DistributedData< PatchData > owned_data
map container for patchdata owned by the current node (layout : id_patch,data)
This header file contains utility functions related to exception handling in the code.
std::vector< int > vector_allgatherv(const std::vector< T > &send_vec, const MPI_Datatype &send_type, std::vector< T > &recv_vec, const MPI_Datatype &recv_type, const MPI_Comm comm)
allgatherv on vector with size query (size querying variant of vector_allgatherv_ks) //TODO add fault...
Definition exchanges.hpp:98
void gather_str(const std::string &send_vec, std::string &recv_vec)
Gathers a string from all nodes and store the result in a std::string.
T mock_value(Engine &eng, T min_bound, T max_bound)
Generates a random mock value within specified bounds.
T & get_check_ref(const std::unique_ptr< T > &ptr, SourceLocation loc=SourceLocation())
Takes a std::unique_ptr and returns a reference to the object it holds. It throws a std::runtime_erro...
Definition memory.hpp:110
ExcptTypes make_except_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Create an exception with a message and a location.
i32 world_rank()
Gives the rank of the current process in the MPI communicator.
Definition worldInfo.cpp:40
namespace for math utility
Definition AABB.hpp:26
std::vector< SinkParticle< Tvec > > to_sink_particles(const SinkEdges< Tvec > &e)
Build an AoS sink list from the current SoA edges (Python API / dump helpers).
void ensure_sink_edges(shamrock::solvergraph::SolverGraphSerializable &sync)
Register sink SoA synchronized edges if missing (idempotent).
void write_shamrock_units_in_phantom_dump(std::optional< shamunits::UnitSystem< Tscal > > &units, PhantomDump &dump, bool bypass_error)
Write shamrock units config into the phantom dump.
void add_sink(SinkEdges< Tvec > &e, typename SinkEdges< Tvec >::Tscal mass, Tvec pos, Tvec velocity, typename SinkEdges< Tvec >::Tscal accretion_radius)
Append one sink to the SoA edges.
void write_shamrock_eos_in_phantom_dump(EOSConfig< Tvec > &cfg, PhantomDump &dump, bool bypass_error)
Write the eos config to th phantom dump header.
constexpr u32 u32_max
u32 max value
Contains traits and utilities for backend related types.
void info_ln(std::string module_name, Types... var2)
Prints a log message with multiple arguments followed by a newline.
Definition logs.hpp:133
Helpers to access SPH sink particles stored as SoA synchronized data edges.
sph kernels
This file contains the definition for the stacktrace related functionality.
shambase::details::NamedBasicStackEntry NamedStackEntry
Alias for shambase::details::NamedBasicStackEntry.
shambase::details::BasicStackEntry StackEntry
Alias for shambase::details::BasicStackEntry.
Class representing a Phantom dump file.
Patch object that contain generic patch information.
Definition Patch.hpp:33
static bool is_in_patch_converted(sycl::vec< T, 3 > val, sycl::vec< T, 3 > min_val, sycl::vec< T, 3 > max_val)
check if particle is in the asked range, given the output of @convert_coord
Definition Patch.hpp:210