39#include <pybind11/cast.h>
40#include <pybind11/numpy.h>
41#include <pybind11/pytypes.h>
47template<
class Tvec,
template<
class>
class SPHKernel>
48void add_instance(py::module &m, std::string name_config, std::string name_model) {
51 using Tscal = shambase::VecComponent<Tvec>;
58 using TConfig =
typename T::Solver::Config;
60 using custom_getter_t = std::function<pybind11::array_t<f64>(
size_t, pybind11::dict &)>;
62 shamlog_debug_ln(
"[Py]",
"registering class :", name_config,
typeid(T).name());
63 shamlog_debug_ln(
"[Py]",
"registering class :", name_model,
typeid(T).name());
65 py::class_<TConfig> config_cls(m, name_config.c_str());
67 shammodels::common::add_json_defs<TConfig>(config_cls);
69 config_cls.def(
"print_status", &TConfig::print_status)
70 .def(
"set_particle_tracking", &TConfig::set_particle_tracking)
72 "set_scheduler_config",
73 [](TConfig &self,
u64 split_crit,
u64 merge_crit) {
74 self.scheduler_conf.split_load_value = split_crit;
75 self.scheduler_conf.merge_load_value = merge_crit;
78 py::arg(
"split_load_value"),
79 py::arg(
"merge_load_value"))
80 .def(
"set_tree_reduction_level", &TConfig::set_tree_reduction_level)
81 .def(
"set_two_stage_search", &TConfig::set_two_stage_search)
82 .def(
"set_show_neigh_stats", &TConfig::set_show_neigh_stats)
84 "set_max_neigh_cache_size",
85 [](TConfig &self,
const py::object &max_neigh_cache_size) {
88 ".set_max_neigh_cache_size() is deprecated,\n"
89 " -> calling this is a no-op,\n"
90 " -> you can remove the call to that function"););
92 .def(
"set_smoothing_length_density_based", &TConfig::set_smoothing_length_density_based)
94 "set_smoothing_length_density_based_neigh_lim",
95 &TConfig::set_smoothing_length_density_based_neigh_lim)
96 .def(
"set_enable_particle_reordering", &TConfig::set_enable_particle_reordering)
97 .def(
"set_particle_reordering_step_freq", &TConfig::set_particle_reordering_step_freq)
98 .def(
"set_show_ghost_zone_graph", &TConfig::set_show_ghost_zone_graph)
99 .def(
"use_luminosity", &TConfig::use_luminosity)
100 .def(
"set_save_dt_to_fields", &TConfig::set_save_dt_to_fields)
101 .def(
"should_save_dt_to_fields", &TConfig::should_save_dt_to_fields)
102 .def(
"set_eos_isothermal", &TConfig::set_eos_isothermal)
103 .def(
"set_eos_adiabatic", &TConfig::set_eos_adiabatic)
104 .def(
"set_eos_polytropic", &TConfig::set_eos_polytropic)
105 .def(
"set_eos_locally_isothermal", &TConfig::set_eos_locally_isothermal)
107 "set_eos_locally_isothermalLP07",
108 [](TConfig &self, Tscal cs0, Tscal q, Tscal r0) {
109 self.set_eos_locally_isothermalLP07(cs0, q, r0);
116 "set_eos_locally_isothermalFA2014",
117 [](TConfig &self, Tscal h_over_r) {
118 self.set_eos_locally_isothermalFA2014(h_over_r);
123 "set_eos_locally_isothermalFA2014_extended",
124 [](TConfig &self, Tscal cs0, Tscal q, Tscal r0,
u32 n_sinks) {
125 self.set_eos_locally_isothermalFA2014_extended(cs0, q, r0, n_sinks);
134 [](TConfig &self, Tscal mu_e) {
135 self.set_eos_fermi(mu_e);
139 .def(
"set_artif_viscosity_None", &TConfig::set_artif_viscosity_None)
141 "set_artif_viscosity_Constant",
142 [](TConfig &self, Tscal alpha_u, Tscal alpha_AV, Tscal beta_AV) {
143 self.set_artif_viscosity_Constant({alpha_u, alpha_AV, beta_AV});
150 "set_artif_viscosity_VaryingMM97",
157 self.set_artif_viscosity_VaryingMM97(
158 {alpha_min, alpha_max, sigma_decay, alpha_u, beta_AV});
161 py::arg(
"alpha_min"),
162 py::arg(
"alpha_max"),
163 py::arg(
"sigma_decay"),
167 "set_artif_viscosity_VaryingCD10",
174 self.set_artif_viscosity_VaryingCD10(
175 {alpha_min, alpha_max, sigma_decay, alpha_u, beta_AV});
178 py::arg(
"alpha_min"),
179 py::arg(
"alpha_max"),
180 py::arg(
"sigma_decay"),
184 "set_artif_viscosity_ConstantDisc",
185 [](TConfig &self, Tscal alpha_AV, Tscal alpha_u, Tscal beta_AV) {
186 self.set_artif_viscosity_ConstantDisc({alpha_AV, alpha_u, beta_AV});
194 [](TConfig &self, Tscal sigma_mhd, Tscal sigma_u) {
195 self.set_IdealMHD({sigma_mhd, sigma_u});
198 py::arg(
"sigma_mhd"),
201 "set_self_gravity_none",
203 self.self_grav_config.set_none();
206 "set_self_gravity_direct",
207 [](TConfig &self,
bool reference_mode =
false) {
208 self.self_grav_config.set_direct(reference_mode);
211 py::arg(
"reference_mode") =
false)
213 "set_self_gravity_mm",
214 [](TConfig &self,
u32 mm_order,
f64 opening_angle,
u32 reduction_level) {
215 self.self_grav_config.set_mm(mm_order, opening_angle, reduction_level);
219 py::arg(
"opening_angle"),
220 py::arg(
"reduction_level") = 3)
222 "set_self_gravity_fmm",
223 [](TConfig &self,
u32 order,
f64 opening_angle,
u32 reduction_level) {
224 self.self_grav_config.set_fmm(order, opening_angle, reduction_level);
228 py::arg(
"opening_angle"),
229 py::arg(
"reduction_level") = 3)
231 "set_self_gravity_sfmm",
236 u32 reduction_level) {
237 self.self_grav_config.set_sfmm(
238 sfmm_order, opening_angle, leaf_lowering, reduction_level);
242 py::arg(
"opening_angle"),
243 py::arg(
"leaf_lowering") =
true,
244 py::arg(
"reduction_level") = 3)
246 "set_softening_plummer",
247 [](TConfig &self,
f64 epsilon) {
248 self.self_grav_config.set_softening_plummer(epsilon);
253 "set_softening_none",
255 self.self_grav_config.set_softening_none();
257 .def(
"set_boundary_free", &TConfig::set_boundary_free)
258 .def(
"set_boundary_periodic", &TConfig::set_boundary_periodic)
259 .def(
"set_boundary_shearing_periodic", &TConfig::set_boundary_shearing_periodic)
261 "set_dust_mode_none",
263 self.dust_config.set_none();
266 "set_dust_mode_monofluid_tvi",
267 [](TConfig &self,
u32 nvar) {
268 self.dust_config.set_monofluid_tvi(nvar);
271 "set_dust_mode_monofluid_complete",
272 [](TConfig &self,
u32 ndust) {
273 self.dust_config.set_monofluid_complete(ndust);
277 .def(
"add_ext_force_point_mass", &TConfig::add_ext_force_point_mass)
279 "add_ext_force_lense_thirring",
280 [](TConfig &self, Tscal central_mass, Tscal Racc, Tscal a_spin, Tvec dir_spin) {
281 self.add_ext_force_lense_thirring(central_mass, Racc, a_spin, dir_spin);
284 py::arg(
"central_mass"),
289 "add_ext_force_shearing_box",
290 [](TConfig &self, Tscal Omega_0, Tscal eta, Tscal q) {
291 self.add_ext_force_shearing_box(Omega_0, eta, q);
298 "add_ext_force_velocity_dissipation",
299 [](TConfig &self, Tscal eta) {
300 self.ext_force_config.add_velocity_dissipation(eta);
305 "add_ext_force_vertical_disc_potential",
306 [](TConfig &self, Tscal central_mass, Tscal R0) {
307 self.ext_force_config.add_vertical_disc_potential(central_mass, R0);
310 py::arg(
"central_mass"),
312 .def(
"set_units", &TConfig::set_units)
316 return self.unit_sys;
320 [](TConfig &self, Tscal cfl_cour) {
321 self.cfl_config.cfl_cour = cfl_cour;
325 [](TConfig &self, Tscal cfl_force) {
326 self.cfl_config.cfl_force = cfl_force;
330 [](TConfig &self, Tscal eta_sink) {
331 self.cfl_config.eta_sink = eta_sink;
333 .def(
"set_cfl_multipler", &TConfig::set_cfl_multipler)
334 .def(
"set_cfl_mult_stiffness", &TConfig::set_cfl_mult_stiffness)
337 [](TConfig &self, Tscal gpart_mass) {
338 self.gpart_mass = gpart_mass;
342 [](TConfig &self,
const Tvec ¢er, Tscal radius) {
343 self.particle_killing.add_kill_sphere(center, radius);
349 std::string sod_tube_analysis_name = name_model +
"_AnalysisSodTube";
350 py::class_<TAnalysisSodTube>(m, sod_tube_analysis_name.c_str())
351 .def(
"compute_L2_dist", [](TAnalysisSodTube &self) -> std::tuple<Tscal, Tvec, Tscal> {
352 auto ret = self.compute_L2_dist();
353 return {ret.rho, ret.v, ret.P};
356 std::string disc_analysis_name = name_model +
"_AnalysisDisc";
357 py::class_<TAnalysisDisc>(m, disc_analysis_name.c_str())
360 [](TAnalysisDisc &self, Tscal Rmin, Tscal Rmax,
u32 Nbin,
ShamrockCtx &ctx) {
361 auto anal = self.compute_analysis(Rmin, Rmax, Nbin, ctx);
364 auto radius = anal.radius.copy_to_stdvec();
365 auto counter = anal.counter.copy_to_stdvec();
366 auto Sigma = anal.Sigma.copy_to_stdvec();
367 auto lx = anal.lx.copy_to_stdvec();
368 auto ly = anal.ly.copy_to_stdvec();
369 auto lz = anal.lz.copy_to_stdvec();
370 auto tilt = anal.tilt.copy_to_stdvec();
371 auto twist = anal.twist.copy_to_stdvec();
372 auto psi = anal.psi.copy_to_stdvec();
373 auto Hsq = anal.Hsq.copy_to_stdvec();
375 dic_out[
"radius"] = radius;
376 dic_out[
"counter"] = counter;
377 dic_out[
"Sigma"] = Sigma;
381 dic_out[
"tilt"] = tilt;
382 dic_out[
"twist"] = twist;
383 dic_out[
"psi"] = psi;
384 dic_out[
"Hsq"] = Hsq;
389 std::string setup_name = name_model +
"_SPHSetup";
390 py::class_<TSPHSetup>(m, setup_name.c_str())
392 "make_generator_lattice_hcp",
393 [](TSPHSetup &self, Tscal dr, Tvec box_min, Tvec box_max,
bool discontinuous) {
394 return self.make_generator_lattice_hcp(dr, {box_min, box_max}, discontinuous);
399 py::arg(
"discontinuous") =
true)
401 "make_generator_lattice_cubic",
402 [](TSPHSetup &self, Tscal dr, Tvec box_min, Tvec box_max) {
403 return self.make_generator_lattice_cubic(dr, {box_min, box_max});
406 "make_generator_disc_mc",
412 std::function<Tscal(Tscal)> sigma_profile,
413 std::function<Tscal(Tscal)> H_profile,
414 std::function<Tscal(Tscal)> rot_profile,
415 std::function<Tscal(Tscal)> cs_profile,
417 Tscal init_h_factor) {
418 return self.make_generator_disc_mc(
427 std::mt19937_64(random_seed),
431 py::arg(
"part_mass"),
432 py::arg(
"disc_mass"),
435 py::arg(
"sigma_profile"),
436 py::arg(
"H_profile"),
437 py::arg(
"rot_profile"),
438 py::arg(
"cs_profile"),
439 py::arg(
"random_seed"),
440 py::arg(
"init_h_factor") = 0.8)
442 "make_generator_from_context",
444 return self.make_generator_from_context(context_other);
451 return self.make_combiner_add(parent1, parent2);
454 "make_modifier_warp_disc",
461 return self.make_modifier_warp_disc(parent, Rwarp, Hwarp, inclination, posangle);
467 py::arg(
"inclination"),
468 py::arg(
"posangle") = 0.)
470 "make_modifier_custom_warp",
473 std::function<Tscal(Tscal)> inc_profile,
474 std::function<Tscal(Tscal)> psi_profile,
475 std::function<Tvec(Tscal)> k_profile) {
476 return self.make_modifier_custom_warp(parent, inc_profile, psi_profile, k_profile);
480 py::arg(
"inc_profile"),
481 py::arg(
"psi_profile"),
482 py::arg(
"k_profile"))
484 "make_modifier_offset",
488 Tvec offset_velocity) {
489 return self.make_modifier_add_offset(parent, offset_postion, offset_velocity);
493 py::arg(
"offset_position"),
494 py::arg(
"offset_velocity"))
496 "make_modifier_filter",
499 std::function<
bool(Tvec)> filter) {
500 return self.make_modifier_filter(parent, filter);
506 "make_modifier_split_part",
512 return self.make_modifier_split_part(parent, n_split, seed, h_scaling);
518 py::arg(
"h_scaling") = 0.6)
523 bool part_reordering,
524 std::optional<u32> gen_step,
525 std::optional<u32> insert_step,
526 std::optional<u64> msg_count_limit,
527 std::optional<u64> msg_size_limit,
528 std::optional<u64> max_msg_size,
531 bool speculative_balancing) {
533 return self.apply_setup_new(
542 speculative_balancing);
544 if (
bool(gen_step)) {
547 "SPHSetup",
"gen_step is ignored when using old setup"));
549 if (
bool(msg_count_limit)) {
552 "SPHSetup",
"msg_count_limit is ignored when using old setup"));
554 if (
bool(msg_size_limit)) {
557 "SPHSetup",
"msg_size_limit is ignored when using old setup"));
559 if (
bool(max_msg_size)) {
562 "SPHSetup",
"max_msg_size is ignored when using old setup"));
564 if (
bool(do_setup_log)) {
567 "SPHSetup",
"do_setup_log is ignored when using old setup"));
569 return self.apply_setup(setup, part_reordering, insert_step);
574 py::arg(
"part_reordering") =
true,
575 py::arg(
"gen_step") = std::nullopt,
576 py::arg(
"insert_step") = std::nullopt,
577 py::arg(
"msg_count_limit") = std::nullopt,
578 py::arg(
"rank_comm_size_limit") = std::nullopt,
579 py::arg(
"max_msg_size") = std::nullopt,
580 py::arg(
"do_setup_log") =
false,
581 py::arg(
"use_new_setup") =
true,
582 py::arg(
"speculative_balancing") =
false);
584 py::class_<T>(m, name_model.c_str())
586 return std::make_unique<T>(ctx);
588 .def(
"init", &T::init)
589 .def(
"init_scheduler", &T::init_scheduler)
592 "evolve_once_override_time",
593 &T::evolve_once_time_expl,
596 .def(
"evolve_once", &T::evolve_once)
599 [](T &self,
f64 target_time,
i32 niter_max) {
600 return self.evolve_until(target_time, niter_max);
602 py::arg(
"target_time"),
604 py::arg(
"niter_max") = -1)
607 [](T &self,
f64 dt) {
608 self.solver.solver_config.set_next_dt(dt);
610 .def(
"timestep", &T::timestep)
611 .def(
"set_cfl_cour", &T::set_cfl_cour, py::arg(
"cfl_cour"))
612 .def(
"set_cfl_force", &T::set_cfl_force, py::arg(
"cfl_force"))
613 .def(
"set_eta_sink", &T::set_eta_sink, py::arg(
"eta_sink"))
614 .def(
"set_particle_mass", &T::set_particle_mass, py::arg(
"gpart_mass"))
615 .def(
"get_particle_mass", &T::get_particle_mass)
616 .def(
"rho_h", &T::rho_h)
617 .def(
"get_hfact", &T::get_hfact)
624 "get_solver_dot_graph",
629 "get_box_dim_fcc_3d",
631 return self.get_box_dim_fcc_3d(dr, xcnt, ycnt, zcnt);
635 [](T &self,
f64 dr, f64_3 box_min, f64_3 box_max) {
636 return self.get_ideal_fcc_box(dr, {box_min, box_max});
640 [](T &self,
f64 dr, f64_3 box_min, f64_3 box_max) {
641 return self.get_ideal_hcp_box(dr, {box_min, box_max});
644 "resize_simulation_box",
645 [](T &self, f64_3 box_min, f64_3 box_max) {
646 return self.resize_simulation_box({box_min, box_max});
650 [](T &self, std::vector<f64_3> pos, std::vector<f64> hpart, std::vector<f64> upart) {
651 return self.push_particle(pos, hpart, upart);
656 std::vector<f64_3> pos,
657 std::vector<f64> hpart,
658 std::vector<f64> upart,
659 std::vector<f64_3> B_on_rho,
660 std::vector<f64> psi_on_ch) {
661 return self.push_particle_mhd(pos, hpart, upart, B_on_rho, psi_on_ch);
665 [](T &self,
f64 dr, f64_3 box_min, f64_3 box_max) {
666 return self.add_cube_fcc_3d(dr, {box_min, box_max});
670 [](T &self,
f64 dr, f64_3 box_min, f64_3 box_max) {
671 return self.add_cube_hcp_3d(dr, {box_min, box_max});
674 "add_cube_hcp_3d_v2",
675 [](T &self,
f64 dr, f64_3 box_min, f64_3 box_max) {
676 return self.add_cube_hcp_3d_v2(dr, {box_min, box_max});
679 "add_disc_3d_keplerian",
690 return self.add_cube_disc_3d(center, Npart, p, rho_0, m, r_in, r_out, q, cmass);
704 return self.add_disc_3d(
705 center, central_mass, Npart, r_in, r_out, disc_mass, p, H_r_in, q);
720 self.add_big_disc_3d(
731 return disc_mass / Npart;
733 .def(
"get_total_part_count", &T::get_total_part_count)
734 .def(
"total_mass_to_part_mass", &T::total_mass_to_part_mass)
736 "set_value_in_a_box",
738 const std::string &field_name,
739 const std::string &field_type,
740 const pybind11::object &value,
744 if (field_type ==
"f64") {
745 f64 val = value.cast<
f64>();
746 self.set_value_in_a_box(field_name, val, {box_min, box_max}, ivar);
747 }
else if (field_type ==
"f64_3") {
748 f64_3 val = value.cast<f64_3>();
749 self.set_value_in_a_box(field_name, val, {box_min, box_max}, ivar);
752 "unknown field type");
755 py::arg(
"field_name"),
756 py::arg(
"field_type"),
763 "set_value_in_sphere",
765 const std::string &field_name,
766 const std::string &field_type,
767 const pybind11::object &value,
770 if (field_type ==
"f64") {
771 f64 val = value.cast<
f64>();
772 self.set_value_in_sphere(field_name, val, center, radius);
773 }
else if (field_type ==
"f64_3") {
774 f64_3 val = value.cast<f64_3>();
775 self.set_value_in_sphere(field_name, val, center, radius);
778 "unknown field type");
782 "set_field_value_lambda_f64",
784 std::string field_name,
785 const std::function<
f64(Tvec)> pos_to_val,
787 return self.template set_field_value_lambda<f64>(
788 std::move(field_name), pos_to_val, offset);
790 py::arg(
"field_name"),
791 py::arg(
"pos_to_val"),
792 py::arg(
"offset") = 0)
794 "set_field_value_lambda_f64_3",
796 std::string field_name,
797 const std::function<f64_3(Tvec)> pos_to_val,
799 return self.template set_field_value_lambda<f64_3>(
800 std::move(field_name), pos_to_val, offset);
802 py::arg(
"field_name"),
803 py::arg(
"pos_to_val"),
804 py::arg(
"offset") = 0)
805 .def(
"overwrite_field_value_f64", &T::template overwrite_field_value<f64>)
806 .def(
"overwrite_field_value_f64_3", &T::template overwrite_field_value<f64_3>)
807 .def(
"remap_positions", &T::remap_positions)
817 const std::string &field_name,
818 const std::string &field_type,
819 const pybind11::object &value,
822 if (field_type ==
"f64") {
823 f64 val = value.cast<
f64>();
824 self.add_kernel_value(field_name, val, center, h_ker);
825 }
else if (field_type ==
"f64_3") {
826 f64_3 val = value.cast<f64_3>();
827 self.add_kernel_value(field_name, val, center, h_ker);
830 "unknown field type");
835 [](T &self,
const std::string &field_name,
const std::string &field_type) {
836 if (field_type ==
"f64") {
837 return py::cast(self.template get_sum<f64>(field_name));
838 }
else if (field_type ==
"f64_3") {
839 return py::cast(self.template get_sum<f64_3>(field_name));
842 "unknown field type");
846 "get_closest_part_to",
847 [](T &self, f64_3 pos) -> f64_3 {
848 return self.get_closest_part_to(pos);
851 "gen_default_config",
853 return typename T::Solver::Config{};
856 "get_current_config",
858 return self.solver.solver_config;
860 .def(
"set_solver_config", &T::set_solver_config)
861 .def(
"add_sink", &T::add_sink)
867 if (!self.solver.storage.sinks.is_empty()) {
868 for (
auto &sink : self.solver.storage.sinks.get()) {
870 sink_dic[
"pos"] = sink.pos;
871 sink_dic[
"velocity"] = sink.velocity;
872 sink_dic[
"sph_acceleration"] = sink.sph_acceleration;
873 sink_dic[
"ext_acceleration"] = sink.ext_acceleration;
874 sink_dic[
"mass"] = sink.mass;
875 sink_dic[
"angular_momentum"] = sink.angular_momentum;
876 sink_dic[
"accretion_radius"] = sink.accretion_radius;
877 list_out.append(sink_dic);
886 return self.solver.solver_config.unit_sys;
891 const std::string &name,
892 const std::string &field_type,
893 const std::vector<Tvec> &positions,
894 const std::optional<custom_getter_t> &custom_getter)
895 -> std::variant<std::vector<f64>, std::vector<f64_3>> {
896 if (custom_getter.has_value()) {
897 if (!(name ==
"custom" && field_type ==
"f64")) {
899 "custom_getter only available for name=custom and field_type=f64");
903 if (field_type ==
"f64") {
905 self.ctx, self.solver.solver_config, self.solver.storage);
906 return render.compute_slice(name, positions, custom_getter).copy_to_stdvec();
909 if (field_type ==
"f64_3") {
911 self.ctx, self.solver.solver_config, self.solver.storage);
912 return render.compute_slice(name, positions, std::nullopt).copy_to_stdvec();
918 py::arg(
"field_type"),
919 py::arg(
"positions"),
920 py::arg(
"custom_getter") = std::nullopt)
922 "render_column_integ",
924 const std::string &name,
925 const std::string &field_type,
927 const std::optional<custom_getter_t> &custom_getter)
928 -> std::variant<std::vector<f64>, std::vector<f64_3>> {
929 if (custom_getter.has_value()) {
930 if (!(name ==
"custom" && field_type ==
"f64")) {
932 "custom_getter only available for name=custom and field_type=f64");
936 if (field_type ==
"f64") {
938 self.ctx, self.solver.solver_config, self.solver.storage);
939 return render.compute_column_integ(name, rays, custom_getter).copy_to_stdvec();
942 if (field_type ==
"f64_3") {
944 self.ctx, self.solver.solver_config, self.solver.storage);
945 return render.compute_column_integ(name, rays, std::nullopt).copy_to_stdvec();
951 py::arg(
"field_type"),
953 py::arg(
"custom_getter") = std::nullopt)
957 const std::string &name,
958 const std::string &field_type,
959 const std::optional<custom_getter_t> &custom_getter)
963 if (custom_getter.has_value()) {
964 if (!(name ==
"custom" && field_type ==
"f64")) {
966 "custom_getter only available for name=custom and field_type=f64");
970 if (field_type ==
"f64") {
972 self.ctx, self.solver.solver_config, self.solver.storage);
973 return render_field_getter.build_field(name, custom_getter);
976 if (field_type ==
"f64_3") {
978 self.ctx, self.solver.solver_config, self.solver.storage);
979 return render_field_getter.build_field(name, custom_getter);
985 py::arg(
"field_type"),
986 py::arg(
"custom_getter") = std::nullopt)
988 "render_azymuthal_integ",
990 const std::string &name,
991 const std::string &field_type,
993 const std::optional<custom_getter_t> &custom_getter)
994 -> std::variant<std::vector<f64>, std::vector<f64_3>> {
995 if (custom_getter.has_value()) {
996 if (!(name ==
"custom" && field_type ==
"f64")) {
998 "custom_getter only available for name=custom and field_type=f64");
1002 if (field_type ==
"f64") {
1004 self.ctx, self.solver.solver_config, self.solver.storage);
1005 return render.compute_azymuthal_integ(name, ring_rays, custom_getter)
1009 if (field_type ==
"f64_3") {
1011 self.ctx, self.solver.solver_config, self.solver.storage);
1012 return render.compute_azymuthal_integ(name, ring_rays, std::nullopt)
1019 py::arg(
"field_type"),
1020 py::arg(
"ring_rays"),
1021 py::arg(
"custom_getter") = std::nullopt)
1023 "render_cartesian_slice",
1025 const std::string &name,
1026 const std::string &field_type,
1032 const std::optional<custom_getter_t> &custom_getter)
1033 -> std::variant<py::array_t<Tscal>> {
1034 if (custom_getter.has_value()) {
1035 if (!(name ==
"custom" && field_type ==
"f64")) {
1037 "custom_getter only available for name=custom and field_type=f64");
1041 if (field_type ==
"f64") {
1042 py::array_t<Tscal> ret({ny, nx});
1045 self.ctx, self.solver.solver_config, self.solver.storage);
1047 std::vector<f64> slice
1049 .compute_slice(name, center, delta_x, delta_y, nx, ny, custom_getter)
1052 for (
u32 iy = 0; iy < ny; iy++) {
1053 for (
u32 ix = 0; ix < nx; ix++) {
1054 ret.mutable_at(iy, ix) = slice[ix + nx * iy];
1061 if (field_type ==
"f64_3") {
1062 py::array_t<Tscal> ret({ny, nx, 3_u32});
1065 self.ctx, self.solver.solver_config, self.solver.storage);
1067 std::vector<f64_3> slice
1068 = render.compute_slice(name, center, delta_x, delta_y, nx, ny, std::nullopt)
1071 for (
u32 iy = 0; iy < ny; iy++) {
1072 for (
u32 ix = 0; ix < nx; ix++) {
1073 ret.mutable_at(iy, ix, 0) = slice[ix + nx * iy][0];
1074 ret.mutable_at(iy, ix, 1) = slice[ix + nx * iy][1];
1075 ret.mutable_at(iy, ix, 2) = slice[ix + nx * iy][2];
1083 return py::array_t<Tscal>({nx, ny});
1086 py::arg(
"field_type"),
1092 py::arg(
"custom_getter") = std::nullopt)
1094 "render_cartesian_column_integ",
1096 const std::string &name,
1097 const std::string &field_type,
1103 const std::optional<custom_getter_t> &custom_getter)
1104 -> std::variant<py::array_t<Tscal>> {
1105 if (custom_getter.has_value()) {
1106 if (!(name ==
"custom" && field_type ==
"f64")) {
1108 "custom_getter only available for name=custom and field_type=f64");
1112 if (field_type ==
"f64") {
1113 py::array_t<Tscal> ret({ny, nx});
1116 self.ctx, self.solver.solver_config, self.solver.storage);
1118 std::vector<f64> slice
1120 .compute_column_integ(
1121 name, center, delta_x, delta_y, nx, ny, custom_getter)
1124 for (
u32 iy = 0; iy < ny; iy++) {
1125 for (
u32 ix = 0; ix < nx; ix++) {
1126 ret.mutable_at(iy, ix) = slice[ix + nx * iy];
1133 if (field_type ==
"f64_3") {
1134 py::array_t<Tscal> ret({ny, nx, 3_u32});
1137 self.ctx, self.solver.solver_config, self.solver.storage);
1139 std::vector<f64_3> slice
1141 .compute_column_integ(
1142 name, center, delta_x, delta_y, nx, ny, std::nullopt)
1145 for (
u32 iy = 0; iy < ny; iy++) {
1146 for (
u32 ix = 0; ix < nx; ix++) {
1147 ret.mutable_at(iy, ix, 0) = slice[ix + nx * iy][0];
1148 ret.mutable_at(iy, ix, 1) = slice[ix + nx * iy][1];
1149 ret.mutable_at(iy, ix, 2) = slice[ix + nx * iy][2];
1157 return py::array_t<Tscal>({nx, ny});
1160 py::arg(
"field_type"),
1166 py::arg(
"custom_getter") = std::nullopt)
1168 "gen_config_from_phantom_dump",
1169 [](T &self,
PhantomDump &dump,
bool bypass_error) {
1170 return self.gen_config_from_phantom_dump(dump, bypass_error);
1173 py::arg(
"bypass_error") =
false,
1175 This function generate a shamrock sph solver config from a phantom dump
1180 bypass_error = false (default) bypass any error in the config
1183 "init_from_phantom_dump",
1184 [](T &self,
PhantomDump &dump, Tscal hpart_fact_load) {
1185 self.init_from_phantom_dump(dump, hpart_fact_load);
1188 py::arg(
"hpart_fact_load") = 1.0)
1190 "make_phantom_dump",
1192 return self.make_phantom_dump();
1194 .def(
"do_vtk_dump", &T::do_vtk_dump)
1195 .def(
"set_debug_dump", &T::set_debug_dump)
1196 .def(
"solver_logs_last_rate", &T::solver_logs_last_rate)
1197 .def(
"solver_logs_last_obj_count", &T::solver_logs_last_obj_count)
1199 "solver_logs_last_system_metrics",
1201 auto system_metrics = self.solver.solve_logs.get_last_system_metrics();
1203 ret[
"duration"] = system_metrics.wall_time;
1204 if (system_metrics.rank_energy_consummed.has_value()) {
1205 ret[
"rank_energy_consummed"] = system_metrics.rank_energy_consummed.value();
1207 if (system_metrics.gpu_energy_consummed.has_value()) {
1208 ret[
"gpu_energy_consummed"] = system_metrics.gpu_energy_consummed.value();
1210 if (system_metrics.cpu_energy_consummed.has_value()) {
1211 ret[
"cpu_energy_consummed"] = system_metrics.cpu_energy_consummed.value();
1213 if (system_metrics.dram_energy_consummed.has_value()) {
1214 ret[
"dram_energy_consummed"] = system_metrics.dram_energy_consummed.value();
1218 .def(
"solver_logs_cumulated_step_time", &T::solver_logs_cumulated_step_time)
1219 .def(
"solver_logs_reset_cumulated_step_time", &T::solver_logs_reset_cumulated_step_time)
1220 .def(
"solver_logs_step_count", &T::solver_logs_step_count)
1221 .def(
"solver_logs_reset_step_count", &T::solver_logs_reset_step_count)
1225 return self.solver.solver_config.get_time();
1230 return self.solver.solver_config.get_dt_sph();
1234 [](T &self, Tscal t) {
1235 return self.solver.solver_config.set_time(t);
1239 [](T &self, Tscal dt) {
1240 return self.solver.solver_config.set_next_dt(dt);
1243 "set_cfl_multipler",
1244 [](T &self, Tscal lambda) {
1245 return self.solver.solver_config.set_cfl_multipler(lambda);
1249 "set_cfl_mult_stiffness",
1250 [](T &self, Tscal cstiff) {
1251 return self.solver.solver_config.set_cfl_mult_stiffness(cstiff);
1255 "change_htolerance",
1256 [](T &self, Tscal in) {
1259 ".change_htolerance(val) is deprecated,\n"
1260 " -> calling this is replaced internally by "
1261 ".change_htolerances(coarse=val, fine=min(val, 1.1))\n"
1263 "https://shamrock-code.github.io/Shamrock/mkdocs/models/sph/"
1264 "smoothing_length_tolerance"););
1265 self.change_htolerances(in, std::min(in, (Tscal) 1.1));
1268 "change_htolerances",
1269 [](T &self, Tscal coarse, Tscal fine) {
1270 self.change_htolerances(coarse, fine);
1276 "make_analysis_sodtube",
1284 return std::make_unique<TAnalysisSodTube>(
1286 self.solver.solver_config,
1287 self.solver.storage,
1296 py::arg(
"direction"),
1297 py::arg(
"time_val"),
1302 "make_analysis_disc",
1304 return std::make_unique<TAnalysisDisc>(
1305 self.ctx, self.solver.solver_config, self.solver.storage);
1307 .def(
"load_from_dump", &T::load_from_dump)
1308 .def(
"dump", &T::dump)
1309 .def(
"get_setup", &T::get_setup)
1311 "get_patch_transform",
1314 return sched.get_patch_transform<Tvec>();
1316 .def(
"apply_momentum_offset", &T::apply_momentum_offset)
1317 .def(
"apply_position_offset", &T::apply_position_offset)
1319 "add_timestep_callback",
1321 std::optional<std::function<
void(
void)>> step_begin_callback,
1322 std::optional<std::function<void(
void)>> step_end_callback) {
1323 self.solver.timestep_callbacks.push_back(
1324 {std::move(step_begin_callback), std::move(step_end_callback)});
1327 py::arg(
"step_begin") = std::nullopt,
1328 py::arg(
"step_end") = std::nullopt);
1331template<
class Tvec,
template<
class>
class SPHKernel>
1332void add_analysisBarycenter_instance(py::module &m,
const std::string &name_model) {
1335 using Tscal = shambase::VecComponent<Tvec>;
1339 py::class_<modules::AnalysisBarycenter<Tvec, SPHKernel>>(m, name_model.c_str())
1340 .def(py::init([](T &model) {
1341 return std::make_unique<modules::AnalysisBarycenter<Tvec, SPHKernel>>(model);
1344 auto result = self.get_barycenter();
1345 return py::make_tuple(result.barycenter, result.mass_disc);
1349template<
class Tvec,
template<
class>
class SPHKernel>
1350void add_analysisEnergyKinetic_instance(py::module &m,
const std::string &name_model) {
1353 using Tscal = shambase::VecComponent<Tvec>;
1356 py::class_<modules::AnalysisEnergyKinetic<Tvec, SPHKernel>>(m, name_model.c_str())
1357 .def(py::init([](T &model) {
1358 return std::make_unique<modules::AnalysisEnergyKinetic<Tvec, SPHKernel>>(model);
1361 return self.get_kinetic_energy();
1365template<
class Tvec,
template<
class>
class SPHKernel>
1366void add_analysisEnergyPotential_instance(py::module &m,
const std::string &name_model) {
1369 using Tscal = shambase::VecComponent<Tvec>;
1372 py::class_<modules::AnalysisEnergyPotential<Tvec, SPHKernel>>(m, name_model.c_str())
1373 .def(py::init([](T &model) {
1374 return std::make_unique<modules::AnalysisEnergyPotential<Tvec, SPHKernel>>(model);
1377 return self.get_potential_energy();
1381template<
class Tvec,
template<
class>
class SPHKernel>
1382void add_analysisTotalMomentum_instance(py::module &m,
const std::string &name_model) {
1385 using Tscal = shambase::VecComponent<Tvec>;
1388 py::class_<modules::AnalysisTotalMomentum<Tvec, SPHKernel>>(m, name_model.c_str())
1389 .def(py::init([](T &model) {
1390 return std::make_unique<modules::AnalysisTotalMomentum<Tvec, SPHKernel>>(model);
1393 return self.get_total_momentum();
1397template<
class Tvec,
template<
class>
class SPHKernel>
1398void add_analysisAngularMomentum_instance(py::module &m,
const std::string &name_model) {
1401 using Tscal = shambase::VecComponent<Tvec>;
1404 py::class_<modules::AnalysisAngularMomentum<Tvec, SPHKernel>>(m, name_model.c_str())
1405 .def(py::init([](T &model) {
1406 return std::make_unique<modules::AnalysisAngularMomentum<Tvec, SPHKernel>>(model);
1409 return self.get_angular_momentum();
1414template<
class Analysis,
typename Tvec,
template<
class>
class SPHKernel>
1416 return Analysis(model);
1419template<
template<
class,
template<
class>
class>
class Analysis>
1420void register_analysis_impl_for_each_kernel(py::module &msph, const char *name_class) {
1433 [](SPHModel_f64_3_M4 &model) {
1434 return analysis_impl<Analysis<f64_3, shammath::M4>>(model);
1441 [](SPHModel_f64_3_M6 &model) {
1442 return analysis_impl<Analysis<f64_3, shammath::M6>>(model);
1449 [](SPHModel_f64_3_M8 &model) {
1450 return analysis_impl<Analysis<f64_3, shammath::M8>>(model);
1457 [](SPHModel_f64_3_C2 &model) {
1458 return analysis_impl<Analysis<f64_3, shammath::C2>>(model);
1465 [](SPHModel_f64_3_C4 &model) {
1466 return analysis_impl<Analysis<f64_3, shammath::C4>>(model);
1473 [](SPHModel_f64_3_C6 &model) {
1474 return analysis_impl<Analysis<f64_3, shammath::C6>>(model);
1481 py::module msph = m.def_submodule(
"model_sph",
"Shamrock sph solver");
1485 add_instance<f64_3, shammath::M4>(msph,
"SPHModel_f64_3_M4_SolverConfig",
"SPHModel_f64_3_M4");
1486 add_instance<f64_3, shammath::M6>(msph,
"SPHModel_f64_3_M6_SolverConfig",
"SPHModel_f64_3_M6");
1487 add_instance<f64_3, shammath::M8>(msph,
"SPHModel_f64_3_M8_SolverConfig",
"SPHModel_f64_3_M8");
1489 add_instance<f64_3, shammath::C2>(msph,
"SPHModel_f64_3_C2_SolverConfig",
"SPHModel_f64_3_C2");
1490 add_instance<f64_3, shammath::C4>(msph,
"SPHModel_f64_3_C4_SolverConfig",
"SPHModel_f64_3_C4");
1491 add_instance<f64_3, shammath::C6>(msph,
"SPHModel_f64_3_C6_SolverConfig",
"SPHModel_f64_3_C6");
1493 using VariantSPHModelBind = std::variant<
1494 std::unique_ptr<Model<f64_3, shammath::M4>>,
1495 std::unique_ptr<Model<f64_3, shammath::M6>>,
1496 std::unique_ptr<Model<f64_3, shammath::M8>>,
1497 std::unique_ptr<Model<f64_3, shammath::C2>>,
1498 std::unique_ptr<Model<f64_3, shammath::C4>>,
1499 std::unique_ptr<Model<f64_3, shammath::C6>>>;
1504 const std::string &vector_type,
1505 const std::string &kernel) -> VariantSPHModelBind {
1506 VariantSPHModelBind ret;
1508 if (vector_type ==
"f64_3" && kernel ==
"M4") {
1509 ret = std::make_unique<Model<f64_3, shammath::M4>>(ctx);
1510 }
else if (vector_type ==
"f64_3" && kernel ==
"M6") {
1511 ret = std::make_unique<Model<f64_3, shammath::M6>>(ctx);
1512 }
else if (vector_type ==
"f64_3" && kernel ==
"M8") {
1513 ret = std::make_unique<Model<f64_3, shammath::M8>>(ctx);
1514 }
else if (vector_type ==
"f64_3" && kernel ==
"C2") {
1515 ret = std::make_unique<Model<f64_3, shammath::C2>>(ctx);
1516 }
else if (vector_type ==
"f64_3" && kernel ==
"C4") {
1517 ret = std::make_unique<Model<f64_3, shammath::C4>>(ctx);
1518 }
else if (vector_type ==
"f64_3" && kernel ==
"C6") {
1519 ret = std::make_unique<Model<f64_3, shammath::C6>>(ctx);
1522 "unknown combination of representation and kernel");
1529 py::arg(
"vector_type"),
1530 py::arg(
"sph_kernel"));
1534 std::shared_ptr<shammodels::sph::modules::ISPHSetupNode>>(msph,
"ISPHSetupNode")
1535 .def(
"get_dot", [](std::shared_ptr<shammodels::sph::modules::ISPHSetupNode> &self) {
1536 return self->get_dot();
1539 py::class_<shammodels::sph::TimestepLog>(msph,
"TimestepLog")
1541 .def_readwrite(
"rank", &shammodels::sph::TimestepLog::rank)
1542 .def_readwrite(
"rate", &shammodels::sph::TimestepLog::rate)
1543 .def_readwrite(
"npart", &shammodels::sph::TimestepLog::npart)
1544 .def_readwrite(
"tcompute", &shammodels::sph::TimestepLog::tcompute)
1545 .def(
"rate_sum", &shammodels::sph::TimestepLog::rate_sum)
1546 .def(
"npart_sum", &shammodels::sph::TimestepLog::npart_sum);
1548 add_analysisBarycenter_instance<f64_3, shammath::M4>(msph,
"AnalysisBarycenter_f64_3_M4");
1549 add_analysisBarycenter_instance<f64_3, shammath::M6>(msph,
"AnalysisBarycenter_f64_3_M6");
1550 add_analysisBarycenter_instance<f64_3, shammath::M8>(msph,
"AnalysisBarycenter_f64_3_M8");
1552 add_analysisBarycenter_instance<f64_3, shammath::C2>(msph,
"AnalysisBarycenter_f64_3_C2");
1553 add_analysisBarycenter_instance<f64_3, shammath::C4>(msph,
"AnalysisBarycenter_f64_3_C4");
1554 add_analysisBarycenter_instance<f64_3, shammath::C6>(msph,
"AnalysisBarycenter_f64_3_C6");
1556 add_analysisEnergyKinetic_instance<f64_3, shammath::M4>(msph,
"AnalysisEnergyKinetic_f64_3_M4");
1557 add_analysisEnergyKinetic_instance<f64_3, shammath::M6>(msph,
"AnalysisEnergyKinetic_f64_3_M6");
1558 add_analysisEnergyKinetic_instance<f64_3, shammath::M8>(msph,
"AnalysisEnergyKinetic_f64_3_M8");
1560 add_analysisEnergyKinetic_instance<f64_3, shammath::C2>(msph,
"AnalysisEnergyKinetic_f64_3_C2");
1561 add_analysisEnergyKinetic_instance<f64_3, shammath::C4>(msph,
"AnalysisEnergyKinetic_f64_3_C4");
1562 add_analysisEnergyKinetic_instance<f64_3, shammath::C6>(msph,
"AnalysisEnergyKinetic_f64_3_C6");
1564 add_analysisEnergyPotential_instance<f64_3, shammath::M4>(
1565 msph,
"AnalysisEnergyPotential_f64_3_M4");
1566 add_analysisEnergyPotential_instance<f64_3, shammath::M6>(
1567 msph,
"AnalysisEnergyPotential_f64_3_M6");
1568 add_analysisEnergyPotential_instance<f64_3, shammath::M8>(
1569 msph,
"AnalysisEnergyPotential_f64_3_M8");
1571 add_analysisEnergyPotential_instance<f64_3, shammath::C2>(
1572 msph,
"AnalysisEnergyPotential_f64_3_C2");
1573 add_analysisEnergyPotential_instance<f64_3, shammath::C4>(
1574 msph,
"AnalysisEnergyPotential_f64_3_C4");
1575 add_analysisEnergyPotential_instance<f64_3, shammath::C6>(
1576 msph,
"AnalysisEnergyPotential_f64_3_C6");
1578 add_analysisTotalMomentum_instance<f64_3, shammath::M4>(msph,
"AnalysisTotalMomentum_f64_3_M4");
1579 add_analysisTotalMomentum_instance<f64_3, shammath::M6>(msph,
"AnalysisTotalMomentum_f64_3_M6");
1580 add_analysisTotalMomentum_instance<f64_3, shammath::M8>(msph,
"AnalysisTotalMomentum_f64_3_M8");
1582 add_analysisTotalMomentum_instance<f64_3, shammath::C2>(msph,
"AnalysisTotalMomentum_f64_3_C2");
1583 add_analysisTotalMomentum_instance<f64_3, shammath::C4>(msph,
"AnalysisTotalMomentum_f64_3_C4");
1584 add_analysisTotalMomentum_instance<f64_3, shammath::C6>(msph,
"AnalysisTotalMomentum_f64_3_C6");
1586 add_analysisAngularMomentum_instance<f64_3, shammath::M4>(
1587 msph,
"AnalysisAngularMomentum_f64_3_M4");
1588 add_analysisAngularMomentum_instance<f64_3, shammath::M6>(
1589 msph,
"AnalysisAngularMomentum_f64_3_M6");
1590 add_analysisAngularMomentum_instance<f64_3, shammath::M8>(
1591 msph,
"AnalysisAngularMomentum_f64_3_M8");
1593 add_analysisAngularMomentum_instance<f64_3, shammath::C2>(
1594 msph,
"AnalysisAngularMomentum_f64_3_C2");
1595 add_analysisAngularMomentum_instance<f64_3, shammath::C4>(
1596 msph,
"AnalysisAngularMomentum_f64_3_C4");
1597 add_analysisAngularMomentum_instance<f64_3, shammath::C6>(
1598 msph,
"AnalysisAngularMomentum_f64_3_C6");
1600 register_analysis_impl_for_each_kernel<modules::AnalysisBarycenter>(msph,
"analysisBarycenter");
1601 register_analysis_impl_for_each_kernel<modules::AnalysisEnergyKinetic>(
1602 msph,
"analysisEnergyKinetic");
1603 register_analysis_impl_for_each_kernel<modules::AnalysisEnergyPotential>(
1604 msph,
"analysisEnergyPotential");
1605 register_analysis_impl_for_each_kernel<modules::AnalysisTotalMomentum>(
1606 msph,
"analysisTotalMomentum");
1607 register_analysis_impl_for_each_kernel<modules::AnalysisAngularMomentum>(
1608 msph,
"analysisAngularMomentum");
AnalysisAngularMomentum class.
AnalysisBarycenter class with one method AnalysisBarycenter.get_barycenter()
AnalysisEnergyKinetic class with one method AnalysisEnergyKinetic.get_kinetic_energy()
AnalysisEnergyPotential class with one method AnalysisEnergyPotential.get_potential_energy()
AnalysisTotalMomentum class with one method AnalysisTotalMomentum.get_total_momentum()
double f64
Alias for double.
std::uint32_t u32
32 bit unsigned integer
std::uint64_t u64
64 bit unsigned integer
std::uint16_t u16
16 bit unsigned integer
std::int32_t i32
32 bit integer
This class is an interface that all SPH setup nodes must implement. It describe an operation associat...
This header file contains utility functions related to exception handling in the code.
void throw_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Throw an exception and append the source location to it.
T & get_check_ref(const std::unique_ptr< T > &ptr, SourceLocation loc=SourceLocation())
Takes a std::unique_ptr and returns a reference to the object it holds. It throws a std::runtime_erro...
std::shared_ptr< ISPHSetupNode > SetupNodePtr
Alias for a shared pointer to an ISPHSetupNode.
namespace for the sph model
Pybind11 include and definitions.
#define Register_pymod(placeholdername)
Register a python module init function using static initialisation.
Utilities to convert JSON objects to Python objects and vice versa. TODO: try to convert directly wit...
Ray representation for intersection testing.
Ring ray representation for intersection testing.
Class representing a Phantom dump file.
Functions related to the MPI communicator.
#define ON_RANK_0(x)
Macro to execute code only on rank 0.