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