57 using Tscal = shambase::VecComponent<Tvec>;
58 static constexpr u32 dim = shambase::VectorProperties<Tvec>::dimension;
59 using Kernel = SPHKernel<Tscal>;
61 using Solver = Solver<Tvec, SPHKernel>;
62 using SolverConfig =
typename Solver::Config;
83 solver.solver_config.scheduler_conf.split_load_value = crit_split;
84 solver.solver_config.scheduler_conf.merge_load_value = crit_merge;
88 template<std::enable_if_t<dim == 3,
int> = 0>
89 inline Tvec get_box_dim_fcc_3d(Tscal dr,
u32 xcnt,
u32 ycnt,
u32 zcnt) {
90 return generic::setup::generators::get_box_dim(dr, xcnt, ycnt, zcnt);
93 inline void set_cfl_cour(Tscal cfl_cour) {
94 solver.solver_config.cfl_config.cfl_cour = cfl_cour;
96 inline void set_cfl_force(Tscal cfl_force) {
97 solver.solver_config.cfl_config.cfl_force = cfl_force;
99 inline void set_eta_sink(Tscal eta_sink) {
100 solver.solver_config.cfl_config.eta_sink = eta_sink;
102 inline void set_particle_mass(Tscal gpart_mass) {
103 solver.solver_config.gpart_mass = gpart_mass;
106 inline Tscal get_particle_mass() {
return solver.solver_config.gpart_mass; }
108 inline void resize_simulation_box(std::pair<Tvec, Tvec> box) {
109 ctx.set_coord_domain_bound({box.first, box.second});
112 SolverConfig gen_config_from_phantom_dump(PhantomDump &phdump,
bool bypass_error);
113 void init_from_phantom_dump(PhantomDump &phdump, Tscal hpart_fact_load = 1.0);
114 PhantomDump make_phantom_dump();
116 void do_vtk_dump(std::string filename,
bool add_patch_world_id) {
117 solver.vtk_do_dump(filename, add_patch_world_id);
120 void set_debug_dump(
bool _do_debug_dump, std::string _debug_dump_filename) {
121 solver.set_debug_dump(_do_debug_dump, _debug_dump_filename);
124 u64 get_total_part_count();
126 f64 total_mass_to_part_mass(
f64 totmass);
128 Tscal get_hfact() {
return Kernel::hfactd; }
130 Tscal rho_h(Tscal h) {
131 return shamrock::sph::rho_h(solver.solver_config.gpart_mass, h, Kernel::hfactd);
134 void add_cube_fcc_3d(Tscal dr, std::pair<Tvec, Tvec> _box);
135 void add_cube_hcp_3d(Tscal dr, std::pair<Tvec, Tvec> _box);
136 void add_cube_hcp_3d_v2(Tscal dr, std::pair<Tvec, Tvec> _box);
138 inline std::unique_ptr<modules::SPHSetup<Tvec, SPHKernel>> get_setup() {
139 return std::make_unique<modules::SPHSetup<Tvec, SPHKernel>>(
140 ctx, solver.solver_config, solver.storage);
162 void add_big_disc_3d(
174 inline void add_sink(Tscal mass, Tvec pos, Tvec velocity, Tscal accretion_radius) {
175 if (solver.storage.sinks.is_empty()) {
176 solver.storage.sinks.set({});
179 shamlog_debug_ln(
"SPH",
"add sink :", mass, pos, velocity, accretion_radius);
181 solver.storage.sinks.get().push_back(
182 {pos, velocity, {}, {}, mass, {}, accretion_radius});
186 inline void set_field_value_lambda(
187 std::string field_name,
const std::function<T(Tvec)> pos_to_val,
const u32 offset) {
197 [&](
u64 patch_id, shamrock::patch::PatchDataLayer &pdat) {
198 PatchDataField<Tvec> &
xyz = pdat.template get_field<Tvec>(ixyz);
199 PatchDataField<T> &f = pdat.template get_field<T>(ifield);
201 auto f_nvar = f.get_nvar();
202 if (offset >= f_nvar) {
204 "offset ({}) is out of bounds for field '{}' with nvar {}",
210 auto acc = f.get_buf().copy_to_stdvec();
211 auto acc_xyz =
xyz.get_buf().copy_to_stdvec();
213 u32 obj_cnt = pdat.get_obj_cnt();
214 for (
u32 i = 0; i < obj_cnt; i++) {
215 acc[i * f_nvar + offset] = pos_to_val(acc_xyz[i]);
218 f.get_buf().copy_from_stdvec(acc);
223 inline void overwrite_field_value(
224 std::string field_name,
225 const std::function<std::vector<T>(py::dict)> field_compute,
235 [&](
u64 patch_id, shamrock::patch::PatchDataLayer &pdat) {
236 PatchDataField<T> &f = pdat.template get_field<T>(ifield);
238 auto f_nvar = f.get_nvar();
239 if (offset >= f_nvar) {
241 "offset ({}) is out of bounds for field '{}' with nvar {}",
247 auto result = field_compute(shamrock::pdat_to_dic(pdat));
249 if (result.size() != f.get_obj_cnt()) {
251 "result.size() != f.get_obj_cnt() ({} != {})",
256 auto acc = f.get_buf().copy_to_stdvec();
258 u32 obj_cnt = pdat.get_obj_cnt();
259 for (
u32 i = 0; i < obj_cnt; i++) {
260 acc[i * f_nvar + offset] = result[i];
263 f.get_buf().copy_from_stdvec(acc);
281 template<std::enable_if_t<dim == 3,
int> = 0>
293 Tscal G = solver.solver_config.get_constant_G();
296 using Config = SolverConfig;
297 using SolverConfigEOS =
typename Config::EOSConfig;
298 using SolverEOS_Adiabatic =
typename SolverConfigEOS::Adiabatic;
299 if (SolverEOS_Adiabatic *eos_config
300 = std::get_if<SolverEOS_Adiabatic>(&solver.solver_config.eos_config.config)) {
302 eos_gamma = eos_config->gamma;
312 auto sigma_profile = [=](Tscal r) {
314 constexpr Tscal sigma_0 = 1;
315 return sigma_0 * sycl::pow(r / r_in, -p);
318 auto cs_law = [=](Tscal r) {
319 return sycl::pow(r / r_in, -q);
322 auto rot_profile = [=](Tscal r) {
323 return sycl::sqrt(G * central_mass / r);
326 Tscal cs_in = H_r_in * rot_profile(r_in);
327 auto cs_profile = [&](Tscal r) {
328 return cs_law(r) * cs_in;
331 std::vector<Out> part_list;
338 return sigma_profile(r);
341 return cs_profile(r);
344 return rot_profile(r);
347 part_list.push_back(out);
350 Tscal part_mass = disc_mass / Npart;
352 using namespace shamrock::patch;
356 std::string log =
"";
363 std::vector<Tvec> vec_pos;
364 std::vector<Tvec> vec_vel;
365 std::vector<Tscal> vec_u;
366 std::vector<Tscal> vec_h;
368 std::vector<Tscal> vec_cs;
370 Tscal G = solver.solver_config.get_constant_G();
372 for (Out o : part_list) {
373 vec_pos.push_back(o.pos + center);
374 vec_vel.push_back(o.velocity);
380 vec_u.push_back(o.cs * o.cs / ( (eos_gamma - 1)));
381 vec_h.push_back(shamrock::sph::h_rho(part_mass, o.rho, Kernel::hfactd));
382 vec_cs.push_back(o.cs);
385 log += shambase::format(
386 "\n patch id={}, add N={} particles", ptch.
id_patch, vec_pos.size());
389 tmp.resize(vec_pos.size());
393 u32 len = vec_pos.size();
395 = tmp.get_field<Tvec>(sched.pdl_old().get_field_idx<Tvec>(
"xyz"));
396 sycl::buffer<Tvec> buf(vec_pos.data(), len);
397 f.override(buf, len);
401 u32 len = vec_pos.size();
403 = tmp.get_field<Tscal>(sched.pdl_old().get_field_idx<Tscal>(
"hpart"));
404 sycl::buffer<Tscal> buf(vec_h.data(), len);
405 f.override(buf, len);
409 u32 len = vec_pos.size();
411 = tmp.get_field<Tscal>(sched.pdl_old().get_field_idx<Tscal>(
"uint"));
412 sycl::buffer<Tscal> buf(vec_u.data(), len);
413 f.override(buf, len);
416 if (solver.solver_config.is_eos_locally_isothermal()) {
417 u32 len = vec_pos.size();
419 = tmp.get_field<Tscal>(sched.pdl_old().get_field_idx<Tscal>(
"soundspeed"));
420 sycl::buffer<Tscal> buf(vec_cs.data(), len);
421 f.override(buf, len);
425 u32 len = vec_pos.size();
427 = tmp.get_field<Tvec>(sched.pdl_old().get_field_idx<Tvec>(
"vxyz"));
428 sycl::buffer<Tvec> buf(vec_vel.data(), len);
429 f.override(buf, len);
432 pdat.insert_elements(tmp);
435 std::string log_gathered =
"";
443 ctx, solver.solver_config, solver.storage)
444 .update_load_balancing();
449 auto [m, M] = sched.get_box_tranform<Tvec>();
464 sched.check_patchdata_locality_correctness();
470 log += shambase::format(
471 "\n patch id={}, N={} particles", p.id_patch, pdat.get_obj_cnt());
482 template<std::enable_if_t<dim == 3,
int> = 0>
483 inline void add_cube_disc_3d(
496 using SolverConfigEOS =
typename Config::EOSConfig;
497 using SolverEOS_Adiabatic =
typename SolverConfigEOS::Adiabatic;
498 if (SolverEOS_Adiabatic *eos_config
499 = std::get_if<SolverEOS_Adiabatic>(&solver.solver_config.eos_config.config)) {
501 eos_gamma = eos_config->gamma;
507 auto cs = [&](Tscal u) {
508 return sycl::sqrt(eos_gamma * (eos_gamma - 1) * u);
511 auto U = [&](Tscal cs) {
512 return cs * cs / (eos_gamma * (eos_gamma - 1));
515 using namespace shamrock::patch;
519 std::string log =
"";
521 sched.for_each_local_patchdata([&](
const Patch &ptch, PatchDataLayer &pdat) {
524 shammath::CoordRange<Tvec> patch_coord = ptransf.to_obj_coord(ptch);
526 std::vector<Tvec> vec_acc;
527 std::vector<Tvec> vec_vel;
528 std::vector<Tscal> vec_u;
530 Tscal G = solver.solver_config.get_constant_G();
533 Npart, p, rho_0, m, r_in, r_out, q, [&](Tvec r, Tscal h) {
534 vec_acc.push_back(r + center);
536 Tscal R = sycl::length(r);
538 Tscal V = sycl::sqrt(G * cmass / R);
540 Tvec etheta = {-r.z(), 0, r.x()};
541 etheta /= sycl::length(etheta);
543 vec_vel.push_back(V * etheta);
546 Tscal cs = cs0 * sycl::pow(R, -q);
548 vec_u.push_back(U(cs));
551 log += shambase::format(
552 "\n patch id={}, add N={} particles", ptch.
id_patch, vec_acc.size());
554 PatchDataLayer tmp(sched.get_layout_ptr_old());
555 tmp.resize(vec_acc.size());
559 u32 len = vec_acc.size();
560 PatchDataField<Tvec> &f
561 = tmp.get_field<Tvec>(sched.pdl_old().get_field_idx<Tvec>(
"xyz"));
562 sycl::buffer<Tvec> buf(vec_acc.data(), len);
563 f.override(buf, len);
567 PatchDataField<Tscal> &f
568 = tmp.get_field<Tscal>(sched.pdl_old().get_field_idx<Tscal>(
"hpart"));
573 u32 len = vec_acc.size();
574 PatchDataField<Tscal> &f
575 = tmp.get_field<Tscal>(sched.pdl_old().get_field_idx<Tscal>(
"uint"));
576 sycl::buffer<Tscal> buf(vec_u.data(), len);
577 f.override(buf, len);
581 u32 len = vec_acc.size();
582 PatchDataField<Tvec> &f
583 = tmp.get_field<Tvec>(sched.pdl_old().get_field_idx<Tvec>(
"vxyz"));
584 sycl::buffer<Tvec> buf(vec_vel.data(), len);
585 f.override(buf, len);
588 pdat.insert_elements(tmp);
591 std::string log_gathered =
"";
595 logger::info_ln(
"Model",
"Push particles : ", log_gathered);
598 modules::ComputeLoadBalanceValue<Tvec, SPHKernel>(
599 ctx, solver.solver_config, solver.storage)
600 .update_load_balancing();
605 auto [m, M] = sched.get_box_tranform<Tvec>();
607 SerialPatchTree<Tvec> sptree(
612 shamrock::ReattributeDataUtility reatrib(sched);
617 reatrib.reatribute_patch_objects(sptree,
"xyz");
620 sched.check_patchdata_locality_correctness();
625 sched.for_each_local_patchdata([&](
const Patch &p, PatchDataLayer &pdat) {
626 log += shambase::format(
627 "\n patch id={}, N={} particles", p.id_patch, pdat.get_obj_cnt());
634 logger::info_ln(
"Model",
"current particle counts : ", log_gathered);
637 void remap_positions(std::function<Tvec(Tvec)> map);
640 std::vector<Tvec> &part_pos_insert,
641 std::vector<Tscal> &part_hpart_insert,
642 std::vector<Tscal> &part_u_insert);
644 void push_particle_mhd(
645 std::vector<Tvec> &part_pos_insert,
646 std::vector<Tscal> &part_hpart_insert,
647 std::vector<Tscal> &part_u_insert,
648 std::vector<Tvec> &part_B_on_rho_insert,
649 std::vector<Tscal> &part_psi_on_ch_insert);
652 inline void set_value_in_a_box(
653 std::string field_name, T val, std::pair<Tvec, Tvec> box,
u32 ivar) {
657 [&](
u64 patch_id, shamrock::patch::PatchDataLayer &pdat) {
658 PatchDataField<Tvec> &
xyz
659 = pdat.template get_field<Tvec>(sched.pdl_old().
get_field_idx<Tvec>(
"xyz"));
662 = pdat.template get_field<T>(sched.pdl_old().
get_field_idx<T>(field_name));
664 if (ivar >= f.get_nvar()) {
666 "You are trying to set value in a box for field ({}) with "
667 "ivar ({}) >= f.get_nvar ({})",
673 u32 nvar = f.get_nvar();
676 auto acc = f.get_buf().template mirror_to<sham::host>();
677 auto acc_xyz =
xyz.get_buf().template mirror_to<sham::host>();
679 for (
u32 i = 0; i < f.get_obj_cnt(); i++) {
682 if (BBAA::is_coord_in_range(r, std::get<0>(box), std::get<1>(box))) {
683 acc[i * nvar + ivar] = val;
691 inline void set_value_in_sphere(std::string field_name, T val, Tvec center, Tscal radius) {
695 [&](
u64 patch_id, shamrock::patch::PatchDataLayer &pdat) {
696 PatchDataField<Tvec> &
xyz
697 = pdat.template get_field<Tvec>(sched.pdl_old().
get_field_idx<Tvec>(
"xyz"));
700 = pdat.template get_field<T>(sched.pdl_old().
get_field_idx<T>(field_name));
702 if (f.get_nvar() != 1) {
706 Tscal r2 = radius * radius;
708 auto acc = f.get_buf().template mirror_to<sham::host>();
709 auto acc_xyz =
xyz.get_buf().template mirror_to<sham::host>();
711 for (
u32 i = 0; i < f.get_obj_cnt(); i++) {
712 Tvec dr = acc_xyz[i] - center;
714 if (sycl::dot(dr, dr) < r2) {
723 inline void add_kernel_value(std::string field_name, T val, Tvec center, Tscal h_ker) {
727 [&](
u64 patch_id, shamrock::patch::PatchDataLayer &pdat) {
728 PatchDataField<Tvec> &
xyz
729 = pdat.template get_field<Tvec>(sched.pdl_old().
get_field_idx<Tvec>(
"xyz"));
732 = pdat.template get_field<T>(sched.pdl_old().
get_field_idx<T>(field_name));
734 if (f.get_nvar() != 1) {
739 auto acc = f.get_buf().template mirror_to<sham::host>();
740 auto acc_xyz =
xyz.get_buf().template mirror_to<sham::host>();
742 for (
u32 i = 0; i < f.get_obj_cnt(); i++) {
743 Tvec dr = acc_xyz[i] - center;
745 Tscal r = sycl::length(dr);
747 acc[i] += val * Kernel::W_3d(r, h_ker);
754 inline T get_sum(std::string name) {
756 T sum = shambase::VectorProperties<T>::get_zero();
760 [&](
u64 patch_id, shamrock::patch::PatchDataLayer &pdat) {
761 PatchDataField<T> &
xyz
762 = pdat.template get_field<T>(sched.pdl_old().
get_field_idx<T>(name));
764 sum +=
xyz.compute_sum();
767 return shamalgs::collective::allreduce_sum(sum);
770 Tvec get_closest_part_to(Tvec pos);
772 inline void apply_momentum_offset(Tvec offset) {
781 sched.for_each_patchdata_nonempty(
782 [&](shamrock::patch::Patch p, shamrock::patch::PatchDataLayer &pdat) {
783 tot_mass += solver.solver_config.gpart_mass * pdat.get_obj_cnt();
786 tot_mass = shamalgs::collective::allreduce_sum(tot_mass);
789 if (!solver.storage.sinks.is_empty()) {
790 for (
auto &s : solver.storage.sinks.get()) {
796 Tvec offset_vel = (tot_mass > 0) ? (offset / tot_mass)
797 : shambase::VectorProperties<Tvec>::get_zero();
800 if (!solver.storage.sinks.is_empty()) {
801 for (
auto &s : solver.storage.sinks.get()) {
802 s.velocity += offset_vel;
807 sched.for_each_patchdata_nonempty(
808 [&](shamrock::patch::Patch p, shamrock::patch::PatchDataLayer &pdat) {
809 PatchDataField<Tvec> &
vxyz = pdat.get_field<Tvec>(ivxyz);
810 vxyz.apply_offset(offset_vel);
814 inline void apply_position_offset(Tvec offset) {
821 if (!solver.storage.sinks.is_empty()) {
822 for (
auto &s : solver.storage.sinks.get()) {
828 sched.for_each_patchdata_nonempty(
829 [&](shamrock::patch::Patch p, shamrock::patch::PatchDataLayer &pdat) {
830 PatchDataField<Tvec> &
xyz = pdat.get_field<Tvec>(ixyz);
831 xyz.apply_offset(offset);
843 inline void set_solver_config(
typename Solver::Config cfg) {
844 if (ctx.is_scheduler_initialized()) {
846 "Cannot change solver config after scheduler is initialized");
849 solver.solver_config = cfg;
852 inline f64 solver_logs_last_rate() {
return solver.solve_logs.get_last_rate(); }
853 inline u64 solver_logs_last_obj_count() {
return solver.solve_logs.get_last_obj_count(); }
854 inline f64 solver_logs_cumulated_step_time() {
855 return solver.solve_logs.get_cumulated_step_time();
857 inline void solver_logs_reset_cumulated_step_time() {
858 solver.solve_logs.reset_cumulated_step_time();
860 inline u64 solver_logs_step_count() {
return solver.solve_logs.get_step_count(); }
861 inline void solver_logs_reset_step_count() { solver.solve_logs.reset_step_count(); }
863 inline void change_htolerances(Tscal in_coarse, Tscal in_fine) {
864 if (in_coarse < in_fine) {
866 "in_coarse ({}) must be greater than in_fine ({})", in_coarse, in_fine));
868 solver.solver_config.htol_up_coarse_cycle = in_coarse;
869 solver.solver_config.htol_up_fine_cycle = in_fine;
891 std::string metadata_user{};
895 nlohmann::json j = nlohmann::json::parse(metadata_user);
897 j.at(
"solver_config").get_to(solver.solver_config);
899 if (!j.at(
"sinks").is_null()) {
900 std::vector<SinkParticle<Tvec>> out;
901 j.at(
"sinks").get_to(out);
902 solver.storage.sinks.set(std::move(out));
905 solver.init_ghost_layout();
907 solver.init_solver_graph();
910 shamlog_debug_ln(
"Sys",
"build local scheduler tables");
924 inline void dump(std::string fname) {
929 solver.update_sync_load_values();
931 nlohmann::json metadata;
932 metadata[
"solver_config"] = solver.solver_config;
934 if (solver.storage.sinks.is_empty()) {
935 metadata[
"sinks"] = nlohmann::json{};
937 metadata[
"sinks"] = solver.storage.sinks.get();
950 f64 evolve_once_time_expl(
f64 t_curr,
f64 dt_input);
954 inline void evolve_once() {
955 solver.evolve_once();
956 solver.print_timestep_logs();
959 inline EvolveUntilResults evolve_until(
960 Tscal target_time,
i32 niter_max,
f64 max_walltime = -1) {
961 return solver.evolve_until(target_time, niter_max, max_walltime);
965 void add_pdat_to_phantom_block(
968 template<
class Tscal>
969 inline void warp_disc(
970 std::vector<Tvec> &pos,
971 std::vector<Tvec> &vel,
976 Tvec k = Tvec(-std::sin(posangle), std::cos(posangle), 0.);
979 u32 len = pos.size();
982 Tscal incl_rad = incl * shambase::constants::pi<Tscal> / 180.;
984 for (
i32 i = 0; i < len; i++) {
986 Tscal R = sycl::sqrt(sycl::dot(R_vec, R_vec));
987 if (R < Rwarp - Hwarp) {
989 }
else if (R < Rwarp + 3. * Hwarp && R > Rwarp - Hwarp) {
993 + sycl::sin(shambase::constants::pi<Tscal> / (2. * Hwarp) * (R - Rwarp)))
994 * sycl::sin(incl_rad));
995 psi = shambase::constants::pi<Tscal>
996 * Rwarp / (4. * Hwarp) * sycl::sin(incl_rad)
997 / sycl::sqrt(1. - (0.5 * sycl::pow(sycl::sin(incl_rad), 2)));
998 Tscal psimax = sycl::max(psimax, psi);
999 Tscal x = pos[i].x();
1000 Tscal y = pos[i].y();
1001 Tscal z = pos[i].z();
1007 Tvec kk = Tvec(0., 0., 1.);
1008 Tvec w = sycl::cross(kk, pos[i]);
1010 pos[i] = pos[i] * sycl::cos(inc) + w * sycl::sin(inc)
1011 + kk * sycl::dot(kk, pos[i]) * (1. - sycl::cos(inc));
1019 inline void rotate_vector(Tvec &u, Tvec &v, Tscal theta) {
1021 Tvec vunit = v / sycl::sqrt(sycl::dot(v, v));
1022 Tvec w = sycl::cross(vunit, u);
1024 u = u * sycl::cos(theta) + w * sycl::sin(theta)
1025 + vunit * sycl::dot(vunit, u) * (1. - sycl::cos(theta));