Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
SolverConfig.hpp
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
10#pragma once
11
20
22#include "config/AVConfig.hpp"
23#include "config/BCConfig.hpp"
24#include "shambackends/math.hpp"
27#include "shambackends/vec.hpp"
46#include <stdexcept>
47#include <variant>
48#include <vector>
49
50namespace shammodels::sph {
51
58 template<class Tvec, template<class> class SPHKernel>
59 struct SolverConfig;
60
66 template<class Tvec>
67 struct SolverStatusVar;
68
74 template<class Tscal>
75 struct CFLConfig {
76
80 Tscal cfl_cour;
81
85 Tscal cfl_force;
86
91
93 Tscal eta_sink = 0.05;
94 };
95
96 template<class Tvec>
98 using Tscal = shambase::VecComponent<Tvec>;
99 struct Sphere {
100 Tvec center;
101 Tscal radius;
102 };
103
104 using kill_t = std::variant<Sphere>;
105
106 std::vector<kill_t> kill_list;
107
108 inline void add_kill_sphere(const Tvec &center, Tscal radius) {
109 kill_list.push_back(Sphere{center, radius});
110 }
111 };
112
113 template<class Tscal>
114 struct DustConfig {
115
116 struct None {};
117
119 u32 ndust;
120 bool pure_diffusion_mode = false;
121 };
122
124 u32 ndust;
125 };
126
128 using Variant = std::variant<None, MonofluidTVI, MonofluidComplete>;
129
130 Variant current_mode = None{};
131
132 inline void set_none() { current_mode = None{}; }
133 inline void set_monofluid_tvi(u32 nvar, bool pure_diffusion_mode = false) {
134 current_mode = MonofluidTVI{nvar, pure_diffusion_mode};
135 }
136 inline void set_monofluid_complete(u32 nvar) { current_mode = MonofluidComplete{nvar}; }
137
138 inline bool is_none() { return std::holds_alternative<None>(current_mode); }
139 inline bool is_monofluid_tvi() { return bool(std::get_if<MonofluidTVI>(&current_mode)); }
140 inline bool is_monofluid_complete() {
141 return bool(std::get_if<MonofluidComplete>(&current_mode));
142 }
143
144 inline void mode_to_json(nlohmann::json &j) const {
145 if (const None *cfg = std::get_if<None>(&current_mode)) {
146 j = {{"type", "none"}};
147 } else if (const MonofluidTVI *cfg = std::get_if<MonofluidTVI>(&current_mode)) {
148 j
149 = {{"type", "monofluid_tvi"},
150 {"ndust", cfg->ndust},
151 {"pure_diffusion_mode", cfg->pure_diffusion_mode}};
152 } else if (
153 const MonofluidComplete *cfg = std::get_if<MonofluidComplete>(&current_mode)) {
154 j = {{"type", "monofluid_complete"}, {"ndust", cfg->ndust}};
155 } else {
157 }
158 }
159
160 inline void mode_from_json(const nlohmann::json &j) {
161 const std::string type = j.at("type").get<std::string>();
162 if (type == "none") {
163 set_none();
164 } else if (type == "monofluid_tvi") {
165 set_monofluid_tvi(
166 j.at("ndust").get<u32>(), j.at("pure_diffusion_mode").get<bool>());
167 } else if (type == "monofluid_complete") {
168 set_monofluid_complete(j.at("ndust").get<u32>());
169 } else {
171 }
172 }
173
174 inline bool has_s_j_field() {
175 return is_monofluid_tvi(); // S_j = sqrt(\rho \epsilon_j)
176 }
177
178 inline bool has_epsilon_field() {
179 return bool(std::get_if<MonofluidComplete>(&current_mode));
180 }
181
182 inline bool has_deltav_field() {
183 return bool(std::get_if<MonofluidComplete>(&current_mode));
184 }
185
186 inline u32 get_dust_nvar() {
187 if (None *cfg = std::get_if<None>(&current_mode)) {
189 "Querying a dust nvar with no dust as config is ... discutable ...");
190 return 0;
191 } else if (MonofluidTVI *cfg = std::get_if<MonofluidTVI>(&current_mode)) {
192 return cfg->ndust;
193 } else if (MonofluidComplete *cfg = std::get_if<MonofluidComplete>(&current_mode)) {
194 return cfg->ndust;
195 } else {
196 shambase::throw_unimplemented("How did you get here ???");
197 }
198 return 0;
199 }
200
202 std::vector<Tscal> stopping_times;
203 };
204
205 struct EpsteinDrag {
206 static constexpr bool supersonic_correction = false;
207 Tscal gamma;
208 std::vector<Tscal> grains_sizes;
209 std::vector<Tscal> grains_densities;
210 };
211
212 std::variant<None, ConstantStoppingTimes, EpsteinDrag> dust_drag_mode = None{};
213
214 inline void drag_mode_to_json(nlohmann::json &j) const {
215 if (std::holds_alternative<None>(dust_drag_mode)) {
216 j = {{"type", "none"}};
217 } else if (
218 const ConstantStoppingTimes *cfg
219 = std::get_if<ConstantStoppingTimes>(&dust_drag_mode)) {
220 j = {{"type", "constant_stopping_times"}, {"stopping_times", cfg->stopping_times}};
221 } else if (const EpsteinDrag *cfg = std::get_if<EpsteinDrag>(&dust_drag_mode)) {
222 j
223 = {{"type", "epstein_drag"},
224 {"gamma", cfg->gamma},
225 {"grains_sizes", cfg->grains_sizes},
226 {"grains_densities", cfg->grains_densities}};
227 } else {
229 }
230 }
231
232 inline void drag_mode_from_json(const nlohmann::json &j) {
233 if (j.at("type").get<std::string>() == "none") {
234 dust_drag_mode = None{};
235 } else if (j.at("type").get<std::string>() == "constant_stopping_times") {
236 dust_drag_mode
237 = ConstantStoppingTimes{j.at("stopping_times").get<std::vector<Tscal>>()};
238 } else if (j.at("type").get<std::string>() == "epstein_drag") {
239 dust_drag_mode = EpsteinDrag{
240 j.at("gamma").get<Tscal>(),
241 j.at("grains_sizes").get<std::vector<Tscal>>(),
242 j.at("grains_densities").get<std::vector<Tscal>>()};
243 } else {
245 }
246 }
247
248 inline void set_drag_constant(ConstantStoppingTimes in) { dust_drag_mode = std::move(in); }
249
250 inline void set_drag_epstein(EpsteinDrag in) { dust_drag_mode = std::move(in); }
251
252 inline void check_config() {
253 bool is_not_none = !is_none();
254 if (is_not_none) {
255
258 "Dust config != None is experimental");
259 } else {
260 ON_RANK_0(
261 logger::warn_ln(
262 "SPH::config",
263 "Dust config != None is work in progress, use it at your own risk"));
264 }
265
266 if (std::holds_alternative<None>(dust_drag_mode)) {
268 "you must select a drag mode for the dust if the dust is on !");
269 } else if (
271 = std::get_if<ConstantStoppingTimes>(&dust_drag_mode)) {
272 if (get_dust_nvar() != cfg->stopping_times.size()) {
274 "stopping_times size does not match the number of dust bins");
275 }
276 } else if (EpsteinDrag *cfg = std::get_if<EpsteinDrag>(&dust_drag_mode)) {
277 if (get_dust_nvar() != cfg->grains_densities.size()) {
279 "grains_densities size does not match the number of dust bins");
280 }
281
282 if (get_dust_nvar() != cfg->grains_sizes.size()) {
284 "grains_sizes size does not match the number of dust bins");
285 }
286 }
287 }
288 }
289 };
290
292 struct DensityBased {};
294 u32 max_neigh_count = 500;
295 };
296
297 using mode = std::variant<DensityBased, DensityBasedNeighLim>;
298
299 mode config = DensityBased{};
300
301 void set_density_based() { config = DensityBased{}; }
302 void set_density_based_neigh_lim(u32 max_neigh_count) {
303 config = DensityBasedNeighLim{max_neigh_count};
304 }
305
306 bool is_density_based_neigh_lim() const {
307 return std::holds_alternative<DensityBasedNeighLim>(config);
308 }
309 };
310
312
313 struct SFMM {
314 u32 order;
315 f64 opening_angle;
316 bool leaf_lowering;
317 u32 reduction_level;
318 };
319
320 struct FMM {
321 u32 order;
322 f64 opening_angle;
323 u32 reduction_level;
324 };
325
326 struct MM {
327 u32 order;
328 f64 opening_angle;
329 u32 reduction_level;
330 };
331
332 struct Direct {
333 bool reference_mode = false;
334 };
335
336 struct None {};
337
338 using mode = std::variant<SFMM, FMM, MM, Direct, None>;
339
340 mode config = None{};
341
342 void set_none() { config = None{}; }
343 void set_direct(bool reference_mode = false) { config = Direct{reference_mode}; }
344 void set_mm(u32 mm_order, f64 opening_angle, u32 reduction_level) {
345 config = MM{
346 .order = mm_order,
347 .opening_angle = opening_angle,
348 .reduction_level = reduction_level};
349 }
350 void set_fmm(u32 order, f64 opening_angle, u32 reduction_level) {
351 config = FMM{
352 .order = order, .opening_angle = opening_angle, .reduction_level = reduction_level};
353 }
354 void set_sfmm(u32 order, f64 opening_angle, bool leaf_lowering, u32 reduction_level) {
355 config = SFMM{
356 .order = order,
357 .opening_angle = opening_angle,
358 .leaf_lowering = leaf_lowering,
359 .reduction_level = reduction_level};
360 }
361
362 bool is_none() const { return std::holds_alternative<None>(config); }
363 bool is_direct() const { return std::holds_alternative<Direct>(config); }
364 bool is_mm() const { return std::holds_alternative<MM>(config); }
365 bool is_fmm() const { return std::holds_alternative<FMM>(config); }
366 bool is_sfmm() const { return std::holds_alternative<SFMM>(config); }
367
368 bool is_sg_on() const { return !is_none(); }
369 bool is_sg_off() const { return is_none(); }
370
372 f64 epsilon;
373 };
374
375 using mode_soft = std::variant<SofteningPlummer>;
376 mode_soft softening_mode = SofteningPlummer{1e-9};
377
378 void set_softening_plummer(f64 epsilon) { softening_mode = SofteningPlummer{epsilon}; }
379 void set_softening_none() { set_softening_plummer(0.); }
380
381 bool is_softening_plummer() const {
382 return std::holds_alternative<SofteningPlummer>(softening_mode);
383 }
384 };
385
386} // namespace shammodels::sph
387
388template<class Tvec>
390
392 using Tscal = shambase::VecComponent<Tvec>;
393
396
398};
399
400template<class Tvec, template<class> class SPHKernel>
402
404 using Tscal = shambase::VecComponent<Tvec>;
406 static constexpr u32 dim = shambase::VectorProperties<Tvec>::dimension;
408 using Kernel = SPHKernel<Tscal>;
410 using u_morton = u32;
411
413
415 static constexpr Tscal Rkern = Kernel::Rkern;
416
419
420 bool track_particles_id = false;
421
422 inline void set_particle_tracking(bool state) { track_particles_id = state; }
423
424 PatchSchedulerConfig scheduler_conf = {};
425
427 // Units Config
429
431 std::optional<shamunits::UnitSystem<Tscal>> unit_sys = {};
432
434 inline void set_units(shamunits::UnitSystem<Tscal> new_sys) { unit_sys = new_sys; }
435
438 if (!unit_sys) {
439 ON_RANK_0(logger::warn_ln("sph::Config", "the unit system is not set"));
441 return ctes.G();
442 } else {
444 }
445 }
446
449 if (!unit_sys) {
450 ON_RANK_0(logger::warn_ln("sph::Config", "the unit system is not set"));
452 return ctes.c();
453 } else {
455 }
456 }
457
460 if (!unit_sys) {
461 ON_RANK_0(logger::warn_ln("sph::Config", "the unit system is not set"));
463 return ctes.mu_0();
464 } else {
466 }
467 }
468
470 // Units Config (END)
472
474 // Particle killing config
476
477 ParticleKillingConfig<Tvec> particle_killing;
478
480 // Particle killing config (END)
482
484 // Solver status variables
486
489
492
494 inline void set_time(Tscal t) { time_state.time = t; }
495
497 inline void set_next_dt(Tscal dt) { time_state.dt_sph = dt; }
498
500 inline Tscal get_time() { return time_state.time; }
501
503 inline Tscal get_dt_sph() { return time_state.dt_sph; }
504
506 inline void set_cfl_multipler(Tscal lambda) { time_state.cfl_multiplier = lambda; }
507
509 inline Tscal get_cfl_multipler() { return time_state.cfl_multiplier; }
510
512 inline void set_cfl_mult_stiffness(Tscal cstiff) {
513 cfl_config.cfl_multiplier_stiffness = cstiff;
514 }
515
517 inline Tscal get_cfl_mult_stiffness() { return cfl_config.cfl_multiplier_stiffness; }
518
519 bool show_cfl_detail = false;
520
522 // Solver status variables (END)
524
526 // MHD Config
528
530 MHDConfig mhd_config = {};
531
533 inline void set_noMHD() {
534 using Tmp = typename MHDConfig::None;
535 mhd_config.set(Tmp{});
536 }
537
540 mhd_config.set(v);
541 }
542
543 inline void set_NonIdealMHD(typename MHDConfig::NonIdealMHD v) { mhd_config.set(v); }
544
546 // MHD Config (END)
548
550 // Dust config
552
553 using DustConfig = DustConfig<Tscal>;
554 DustConfig dust_config = {};
555
557 // Dust config (END)
559
561 // Self gravity config
563
564 SelfGravConfig self_grav_config = SelfGravConfig{};
565
567 // Self gravity config (END)
569
571 // Tree config
573
576
578 inline void set_tree_reduction_level(u32 level) { tree_reduction_level = level; }
580 inline void set_two_stage_search(bool enable) { use_two_stage_search = enable; }
581
582 bool show_neigh_stats = false;
583 inline void set_show_neigh_stats(bool enable) { show_neigh_stats = enable; }
585 // Tree config (END)
587
589 // Solver behavior config
591
601
602 SmoothingLengthConfig smoothing_length_config;
603
604 inline void set_smoothing_length_density_based() {
605 smoothing_length_config.set_density_based();
606 }
607 inline void set_smoothing_length_density_based_neigh_lim(u32 max_neigh_count) {
608 smoothing_length_config.set_density_based_neigh_lim(max_neigh_count);
609 }
610
611 bool enable_particle_reordering = false;
612 inline void set_enable_particle_reordering(bool enable) { enable_particle_reordering = enable; }
613 u64 particle_reordering_step_freq = 1000;
614 inline void set_particle_reordering_step_freq(u64 freq) {
615 if (freq == 0) {
617 "particle_reordering_step_freq cannot be zero");
618 }
619 particle_reordering_step_freq = freq;
620 }
621
622 bool save_dt_to_fields = false;
623 inline void set_save_dt_to_fields(bool enable) { save_dt_to_fields = enable; }
624 inline bool should_save_dt_to_fields() const { return save_dt_to_fields; }
625
626 bool show_ghost_zone_graph = false;
627 inline void set_show_ghost_zone_graph(bool enable) { show_ghost_zone_graph = enable; }
628
630 // Solver behavior config (END)
632
634 // EOS Config
636
639
642
645 using T = typename EOSConfig::LocallyIsothermal;
646 return bool(std::get_if<T>(&eos_config.config));
647 }
648
650 inline bool is_eos_adiabatic() {
651 using T = typename EOSConfig::Adiabatic;
652 return bool(std::get_if<T>(&eos_config.config));
653 }
654
656 inline bool is_eos_polytropic() {
657 using T = typename EOSConfig::Polytropic;
658 return bool(std::get_if<T>(&eos_config.config));
659 }
660
662 inline bool is_eos_isothermal() {
663 using T = typename EOSConfig::Isothermal;
664 return bool(std::get_if<T>(&eos_config.config));
665 }
666
668 inline bool is_eos_fermi() {
669 using T = typename EOSConfig::Fermi;
670 return bool(std::get_if<T>(&eos_config.config));
671 }
672
678 inline void set_eos_isothermal(Tscal cs) { eos_config.set_isothermal(cs); }
679
685 inline void set_eos_adiabatic(Tscal gamma) { eos_config.set_adiabatic(gamma); }
686
692 inline void set_eos_polytropic(Tscal K, Tscal gamma) { eos_config.set_polytropic(K, gamma); }
693
697 inline void set_eos_locally_isothermal() { eos_config.set_locally_isothermal(); }
698
708 eos_config.set_locally_isothermalLP07(cs0, q, r0);
709 }
710
719 eos_config.set_locally_isothermalFA2014(h_over_r);
720 }
721
732 Tscal cs0, Tscal q, Tscal r0, u32 n_sinks) {
733 eos_config.set_locally_isothermalFA2014_extended(cs0, q, r0, n_sinks);
734 }
735
741 inline void set_eos_fermi(Tscal mu_e) { eos_config.set_fermi(mu_e); }
742
744 // EOS Config (END)
746
748 // Artificial viscosity Config
750
763
766
771 using Tmp = typename AVConfig::None;
772 artif_viscosity.set(Tmp{});
773 }
774
780 inline void set_artif_viscosity_Constant(typename AVConfig::Constant v) {
781 artif_viscosity.set(v);
782 }
783
790 inline void set_artif_viscosity_VaryingMM97(typename AVConfig::VaryingMM97 v) {
791 artif_viscosity.set(v);
792 }
793
800 inline void set_artif_viscosity_VaryingCD10(typename AVConfig::VaryingCD10 v) {
801 artif_viscosity.set(v);
802 }
803
808 inline void set_artif_viscosity_ConstantDisc(typename AVConfig::ConstantDisc v) {
809 artif_viscosity.set(v);
810 }
811
813 // Artificial viscosity Config (END)
815
817 // Boundary Config
819
824
831
835 inline void set_boundary_free() { boundary_config.set_free(); }
836
840 inline void set_boundary_periodic() { boundary_config.set_periodic(); }
841
853 inline void set_boundary_shearing_periodic(i32_3 shear_base, i32_3 shear_dir, Tscal speed) {
854 boundary_config.set_shearing_periodic(shear_base, shear_dir, speed);
855 }
856
858 // Boundary Config (END)
860
862 // Ext force Config
864
877
882
889 inline void add_ext_force_point_mass(Tscal central_mass, Tscal Racc) {
890 ext_force_config.add_point_mass(central_mass, Racc);
891 }
892
899 inline void add_ext_force_paczynski_wiita(Tscal central_mass, Tvec central_pos, Tscal Racc) {
900 ext_force_config.add_paczynski_wiita(central_mass, central_pos, Racc);
901 }
902
912 Tscal central_mass, Tscal Racc, Tscal a_spin, Tvec dir_spin) {
913 ext_force_config.add_lense_thirring(central_mass, Racc, a_spin, dir_spin);
914 }
915
923 inline void add_ext_force_shearing_box(Tscal Omega_0, Tscal eta, Tscal q) {
924 ext_force_config.add_shearing_box(Omega_0, eta, q);
925 }
926
928 // Ext force Config (END)
930
932 // Debug dump config
934
936 bool do_debug_dump = false;
937
939 std::string debug_dump_filename = "";
940
945 inline void set_debug_dump(bool _do_debug_dump, std::string _debug_dump_filename) {
946 this->do_debug_dump = _do_debug_dump;
947 this->debug_dump_filename = _debug_dump_filename;
948 }
949
951 inline constexpr bool do_MHD_debug() { return false; }
952
954 // Debug dump config (END)
956
959
963 inline bool has_field_uint() {
964 // no barotropic for now
965 return true;
966 }
967
969 inline bool has_field_alphaAV() { return artif_viscosity.has_alphaAV_field(); }
970
972 inline bool has_field_divv() { return artif_viscosity.has_alphaAV_field(); }
973
975 inline bool has_field_dtdivv() { return artif_viscosity.has_dtdivv_field(); }
976
978 inline bool has_field_curlv() { return artif_viscosity.has_curlv_field() && (dim == 3); }
979
981 inline bool has_axyz_in_ghost() { return has_field_dtdivv(); }
982
984 inline bool has_field_soundspeed() {
985 return artif_viscosity.has_field_soundspeed() || is_eos_locally_isothermal();
986 }
987
989 inline bool has_field_B_on_rho() { return mhd_config.has_B_field() && (dim == 3); }
990
992 inline bool has_field_psi_on_ch() { return mhd_config.has_psi_field(); }
993
995 inline bool has_field_divB() { return mhd_config.has_divB_field(); }
996
998 inline bool has_field_curlB() { return mhd_config.has_curlB_field() && (dim == 3); }
999
1001 inline bool has_field_dtdivB() { return mhd_config.has_dtdivB_field(); }
1002
1005 inline void use_luminosity(bool enable) { compute_luminosity = enable; }
1006
1008 inline void print_status() {
1009 if (shamcomm::world_rank() != 0) {
1010 return;
1011 }
1012 logger::raw_ln("----- SPH Solver configuration -----");
1013 logger::raw_ln(nlohmann::json{*this}.dump(4));
1014 logger::raw_ln("------------------------------------");
1015 }
1016
1017 inline void check_config() {
1018 dust_config.check_config();
1019
1020 if (track_particles_id && false /*particle injection when added*/) {
1022 "particle injection is not yet compatible with particle id tracking");
1023 }
1024
1025 if (track_particles_id) {
1026 shamrock::experimental_feature_check("Particle tracking is experimental");
1027 }
1028
1029 if (!self_grav_config.is_none()) {
1031 "Self gravity is experimental, please enable experimental features to use it");
1032 }
1033 }
1034
1035 void set_layout(shamrock::patch::PatchDataLayerLayout &pdl);
1036 void set_ghost_layout(shamrock::patch::PatchDataLayerLayout &ghost_layout);
1037};
1038
1039namespace shammodels::sph {
1040
1047 template<class Tscal>
1048 inline void to_json(nlohmann::json &j, const CFLConfig<Tscal> &p) {
1049 j = nlohmann::json{
1050 {"cfl_cour", p.cfl_cour},
1051 {"cfl_force", p.cfl_force},
1052 {"cfl_multiplier_stiffness", p.cfl_multiplier_stiffness},
1053 {"eta_sink", p.eta_sink}};
1054 }
1055
1062 template<class Tscal>
1063 inline void from_json(const nlohmann::json &j, CFLConfig<Tscal> &p) {
1064 j.at("cfl_cour").get_to<Tscal>(p.cfl_cour);
1065 j.at("cfl_force").get_to<Tscal>(p.cfl_force);
1066 j.at("cfl_multiplier_stiffness").get_to<Tscal>(p.cfl_multiplier_stiffness);
1067
1068 if (j.contains("eta_sink")) {
1069 j.at("eta_sink").get_to<Tscal>(p.eta_sink);
1070 } else {
1071 // Already set to default value
1072 ON_RANK_0(shamlog_warn_ln(
1073 "SPHConfig", "eta_sink not found when deserializing, defaulting to", p.eta_sink));
1074 }
1075 }
1076
1083 template<class Tvec>
1084 inline void to_json(nlohmann::json &j, const SolverStatusVar<Tvec> &p) {
1085 j = nlohmann::json{
1086 {"time", p.time}, {"dt_sph", p.dt_sph}, {"cfl_multiplier", p.cfl_multiplier}};
1087 }
1088
1095 template<class Tvec>
1096 inline void from_json(const nlohmann::json &j, SolverStatusVar<Tvec> &p) {
1097 using Tscal = typename SolverStatusVar<Tvec>::Tscal;
1098 j.at("time").get_to<Tscal>(p.time);
1099 j.at("dt_sph").get_to<Tscal>(p.dt_sph);
1100 j.at("cfl_multiplier").get_to<Tscal>(p.cfl_multiplier);
1101 }
1102
1103 // JSON serialization for ParticleKillingConfig
1104 template<class Tvec>
1105 inline void to_json(nlohmann::json &j, const ParticleKillingConfig<Tvec> &p) {
1106 j = nlohmann::json::array();
1107 for (const auto &kill : p.kill_list) {
1108 if (std::holds_alternative<typename ParticleKillingConfig<Tvec>::Sphere>(kill)) {
1109 const auto &sphere = std::get<typename ParticleKillingConfig<Tvec>::Sphere>(kill);
1110 j.push_back(
1111 {{"type", "sphere"}, {"center", sphere.center}, {"radius", sphere.radius}});
1112 }
1113 // If more types are added to kill_t, handle them here
1114 }
1115 }
1116
1117 template<class Tvec>
1118 inline void from_json(const nlohmann::json &j, ParticleKillingConfig<Tvec> &p) {
1119 p.kill_list.clear();
1120 for (const auto &item : j) {
1121 std::string type = item.at("type").get<std::string>();
1122 if (type == "sphere") {
1124 item.at("center").get_to(sphere.center);
1125 item.at("radius").get_to(sphere.radius);
1126 p.kill_list.push_back(sphere);
1127 }
1128 // If more types are added to kill_t, handle them here
1129 }
1130 }
1131
1132 // JSON serialization for SmoothingLengthConfig
1133 inline void to_json(nlohmann::json &j, const SmoothingLengthConfig &p) {
1135 = std::get_if<SmoothingLengthConfig::DensityBased>(&p.config)) {
1136 j = {
1137 {"type", "density_based"},
1138 };
1139
1140 } else if (
1142 = std::get_if<SmoothingLengthConfig::DensityBasedNeighLim>(&p.config)) {
1143
1144 j = {
1145 {"type", "density_based_neigh_lim"},
1146 {"max_neigh_count", conf->max_neigh_count},
1147 };
1148 } else {
1150 }
1151 }
1152
1153 inline void from_json(const nlohmann::json &j, SmoothingLengthConfig &p) {
1154 if (j.at("type").get<std::string>() == "density_based") {
1156 } else if (j.at("type").get<std::string>() == "density_based_neigh_lim") {
1157 p.config
1158 = SmoothingLengthConfig::DensityBasedNeighLim{j.at("max_neigh_count").get<u32>()};
1159 } else {
1161 }
1162 }
1163
1165 inline void to_json(nlohmann::json &j, const SelfGravConfig &p) {
1166 if (const SelfGravConfig::SFMM *conf = std::get_if<SelfGravConfig::SFMM>(&p.config)) {
1167 j = {
1168 {"type", "sfmm"},
1169 {"order", conf->order},
1170 {"opening_angle", conf->opening_angle},
1171 {"reduction_level", conf->reduction_level},
1172 {"leaf_lowering", conf->leaf_lowering},
1173 };
1174 } else if (const SelfGravConfig::FMM *conf = std::get_if<SelfGravConfig::FMM>(&p.config)) {
1175 j = {
1176 {"type", "fmm"},
1177 {"order", conf->order},
1178 {"opening_angle", conf->opening_angle},
1179 {"reduction_level", conf->reduction_level},
1180 };
1181 } else if (const SelfGravConfig::MM *conf = std::get_if<SelfGravConfig::MM>(&p.config)) {
1182 j = {
1183 {"type", "mm"},
1184 {"order", conf->order},
1185 {"opening_angle", conf->opening_angle},
1186 {"reduction_level", conf->reduction_level},
1187 };
1188 } else if (
1189 const SelfGravConfig::Direct *conf = std::get_if<SelfGravConfig::Direct>(&p.config)) {
1190 j = {
1191 {"type", "direct"},
1192 {"reference_mode", conf->reference_mode},
1193 };
1194 } else if (
1195 const SelfGravConfig::None *conf = std::get_if<SelfGravConfig::None>(&p.config)) {
1196 j = {
1197 {"type", "none"},
1198 };
1199 }
1200
1201 if (const SelfGravConfig::SofteningPlummer *conf
1202 = std::get_if<SelfGravConfig::SofteningPlummer>(&p.softening_mode)) {
1203 j["softening_mode"] = "plummer";
1204 j["softening_length"] = conf->epsilon;
1205 } else {
1207 }
1208 }
1209
1211 inline void from_json(const nlohmann::json &j, SelfGravConfig &p) {
1212 if (j.at("type").get<std::string>() == "sfmm") {
1213 p.config = SelfGravConfig::SFMM{
1214 .order = j.at("order").get<u32>(),
1215 .opening_angle = j.at("opening_angle").get<f64>(),
1216 .leaf_lowering = j.at("leaf_lowering").get<bool>(),
1217 .reduction_level = j.at("reduction_level").get<u32>()};
1218 } else if (j.at("type").get<std::string>() == "fmm") {
1219 p.config = SelfGravConfig::FMM{
1220 .order = j.at("order").get<u32>(),
1221 .opening_angle = j.at("opening_angle").get<f64>(),
1222 .reduction_level = j.at("reduction_level").get<u32>()};
1223 } else if (j.at("type").get<std::string>() == "mm") {
1224 p.config = SelfGravConfig::MM{
1225 .order = j.at("order").get<u32>(),
1226 .opening_angle = j.at("opening_angle").get<f64>(),
1227 .reduction_level = j.at("reduction_level").get<u32>()};
1228 } else if (j.at("type").get<std::string>() == "direct") {
1229 p.config = SelfGravConfig::Direct{j.at("reference_mode").get<bool>()};
1230 } else if (j.at("type").get<std::string>() == "none") {
1231 p.config = SelfGravConfig::None{};
1232 } else {
1234 "Invalid self gravity type: " + j.at("type").get<std::string>());
1235 }
1236
1237 if (j.contains("softening_mode")) {
1238 std::string softening_mode = j.at("softening_mode").get<std::string>();
1239 if (softening_mode == "plummer") {
1240 p.softening_mode
1241 = SelfGravConfig::SofteningPlummer{j.at("softening_length").get<f64>()};
1242 } else {
1244 "Invalid softening mode: " + softening_mode);
1245 }
1246 }
1247 }
1248
1249 // JSON serialization for DustConfig
1250 template<class Tvec>
1251 inline void to_json(nlohmann::json &j, const DustConfig<Tvec> &p) {
1252 j = {};
1253
1254 p.mode_to_json(j["mode"]);
1255 p.drag_mode_to_json(j["drag_mode"]);
1256 }
1257
1258 template<class Tvec>
1259 inline void from_json(const nlohmann::json &j, DustConfig<Tvec> &p) {
1260 p.mode_from_json(j.at("mode"));
1261 p.drag_mode_from_json(j.at("drag_mode"));
1262 }
1263
1270 template<class Tvec, template<class> class SPHKernel>
1271 inline void to_json(nlohmann::json &j, const SolverConfig<Tvec, SPHKernel> &p) {
1273 using Tkernel = typename T::Kernel;
1274
1275 std::string kernel_id = shambase::get_type_name<Tkernel>();
1276 std::string type_id = shambase::get_type_name<Tvec>();
1277
1278 j = nlohmann::json{
1279 // used for type checking
1280 {"kernel_id", kernel_id},
1281 {"type_id", type_id},
1282 // scheduler config
1283 {"scheduler_config", p.scheduler_conf},
1284 // actual data stored in the json
1285 {"gpart_mass", p.gpart_mass},
1286 {"cfl_config", p.cfl_config},
1287 {"unit_sys", p.unit_sys},
1288 {"time_state", p.time_state},
1289 {"show_cfl_detail", p.show_cfl_detail},
1290 // mhd config
1291 {"mhd_config", p.mhd_config},
1292 // dust config
1293 {"dust_config", p.dust_config},
1294 // self gravity config
1295 {"self_grav_config", p.self_grav_config},
1296 // tree config
1297 {"tree_reduction_level", p.tree_reduction_level},
1298 {"use_two_stage_search", p.use_two_stage_search},
1299 {"show_neigh_stats", p.show_neigh_stats},
1300 // solver behavior config
1301 {"combined_dtdiv_divcurlv_compute", p.combined_dtdiv_divcurlv_compute},
1302 {"htol_up_coarse_cycle", p.htol_up_coarse_cycle},
1303 {"htol_up_fine_cycle", p.htol_up_fine_cycle},
1304 {"epsilon_h", p.epsilon_h},
1305 {"smoothing_length_config", p.smoothing_length_config},
1306 {"h_iter_per_subcycles", p.h_iter_per_subcycles},
1307 {"h_max_subcycles_count", p.h_max_subcycles_count},
1308
1309 {"enable_particle_reordering", p.enable_particle_reordering},
1310 {"particle_reordering_step_freq", p.particle_reordering_step_freq},
1311
1312 {"save_dt_to_fields", p.save_dt_to_fields},
1313 {"show_ghost_zone_graph", p.show_ghost_zone_graph},
1314
1315 {"eos_config", p.eos_config},
1316
1317 {"artif_viscosity", p.artif_viscosity},
1318 {"boundary_config", p.boundary_config},
1319 {"ext_force_config", p.ext_force_config},
1320
1321 {"do_debug_dump", p.do_debug_dump},
1322 {"debug_dump_filename", p.debug_dump_filename},
1323 // particle killing config
1324 {"particle_killing", p.particle_killing},
1325 };
1326 }
1327
1334 template<class Tvec, template<class> class SPHKernel>
1335 inline void from_json(const nlohmann::json &j, SolverConfig<Tvec, SPHKernel> &p) {
1337 using Tkernel = typename T::Kernel;
1338
1339 // type checking
1340 if (j.contains("kernel_id")) {
1341
1342 std::string kernel_id = j.at("kernel_id").get<std::string>();
1343
1344 if (kernel_id != shambase::get_type_name<Tkernel>()) {
1346 "Invalid type to deserialize, wanted " + shambase::get_type_name<Tvec>()
1347 + " but got " + kernel_id);
1348 }
1349 }
1350
1351 if (j.contains("type_id")) {
1352
1353 std::string type_id = j.at("type_id").get<std::string>();
1354
1355 if (type_id != shambase::get_type_name<Tvec>()) {
1357 "Invalid type to deserialize, wanted " + shambase::get_type_name<Tvec>()
1358 + " but got " + type_id);
1359 }
1360 }
1361
1362 bool has_used_defaults = false;
1363 bool has_updated_config = false;
1364
1365 auto _get_to_if_contains = [&](const std::string &key, auto &value) {
1366 shamrock::get_to_if_contains(j, key, value, has_used_defaults);
1367 };
1368
1369 auto _get_to_if_contains_fallbacks = [&](const std::string &key,
1370 auto &value,
1371 std::initializer_list<const char *> fallbacks) {
1373 j, key, value, fallbacks, has_used_defaults, has_updated_config);
1374 };
1375
1376 _get_to_if_contains("scheduler_config", p.scheduler_conf);
1377
1378 // actual data stored in the json
1379 _get_to_if_contains("gpart_mass", p.gpart_mass);
1380 _get_to_if_contains("cfl_config", p.cfl_config);
1381 _get_to_if_contains("unit_sys", p.unit_sys);
1382 _get_to_if_contains("time_state", p.time_state);
1383 _get_to_if_contains("show_cfl_detail", p.show_cfl_detail);
1384 _get_to_if_contains("mhd_config", p.mhd_config);
1385 _get_to_if_contains("dust_config", p.dust_config);
1386 _get_to_if_contains("self_grav_config", p.self_grav_config);
1387 _get_to_if_contains("tree_reduction_level", p.tree_reduction_level);
1388 _get_to_if_contains("use_two_stage_search", p.use_two_stage_search);
1389 _get_to_if_contains("show_neigh_stats", p.show_neigh_stats);
1390 _get_to_if_contains("combined_dtdiv_divcurlv_compute", p.combined_dtdiv_divcurlv_compute);
1391
1392 // Try new names first, fall back to old names for backward compatibility
1393 _get_to_if_contains_fallbacks(
1394 "htol_up_coarse_cycle", p.htol_up_coarse_cycle, {"htol_up_tol"});
1395 _get_to_if_contains_fallbacks("htol_up_fine_cycle", p.htol_up_fine_cycle, {"htol_up_iter"});
1396
1397 _get_to_if_contains("epsilon_h", p.epsilon_h);
1398 _get_to_if_contains("smoothing_length_config", p.smoothing_length_config);
1399 _get_to_if_contains("h_iter_per_subcycles", p.h_iter_per_subcycles);
1400 _get_to_if_contains("h_max_subcycles_count", p.h_max_subcycles_count);
1401 _get_to_if_contains("enable_particle_reordering", p.enable_particle_reordering);
1402 _get_to_if_contains("particle_reordering_step_freq", p.particle_reordering_step_freq);
1403 _get_to_if_contains("save_dt_to_fields", p.save_dt_to_fields);
1404 _get_to_if_contains("show_ghost_zone_graph", p.show_ghost_zone_graph);
1405 _get_to_if_contains("eos_config", p.eos_config);
1406 _get_to_if_contains("artif_viscosity", p.artif_viscosity);
1407 _get_to_if_contains("boundary_config", p.boundary_config);
1408 _get_to_if_contains("ext_force_config", p.ext_force_config);
1409 _get_to_if_contains("do_debug_dump", p.do_debug_dump);
1410 _get_to_if_contains("debug_dump_filename", p.debug_dump_filename);
1411 _get_to_if_contains("particle_killing", p.particle_killing);
1412
1413 if (has_used_defaults || has_updated_config) {
1414 if (shamcomm::world_rank() == 0) {
1416 "SPH::SolverConfig",
1417 shamrock::log_json_changes(p, j, has_used_defaults, has_updated_config));
1418 }
1419 }
1420 }
1421
1422} // namespace shammodels::sph
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
A Compressed Leaf Bounding Volume Hierarchy (CLBVH) for neighborhood queries.
Defines a unit system.
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.
ExcptTypes make_except_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Create an exception with a message and a location.
void throw_unimplemented(SourceLocation loc=SourceLocation{})
Throw a std::runtime_error saying that the function is unimplemented.
i32 world_rank()
Gives the rank of the current process in the MPI communicator.
Definition worldInfo.cpp:40
namespace for the sph model
void to_json(nlohmann::json &j, const EOSConfig< Tvec > &p)
Serialize EOSConfig to json.
Definition EOSConfig.cpp:43
void get_to_if_contains(const nlohmann::json &j, const std::string &key, T &value, bool &has_used_defaults)
void experimental_feature_check(const std::string &message, SourceLocation loc=SourceLocation{})
Check if experimental features are enabled, if not throw with the given message.
std::string log_json_changes(const nlohmann::json &j_current, const nlohmann::json &j, bool has_used_defaults, bool has_updated_config)
Shown the changes between two JSON objects to log config changes.
bool are_experimental_features_allowed()
Allow the use of experimental features.
void get_to_if_contains_fallbacks(const nlohmann::json &j, const std::string &key, T &value, std::initializer_list< const char * > fallbacks, bool &has_used_defaults, bool &has_updated_config)
Contains traits and utilities for backend related types.
void raw_ln(Types... var2)
Prints a log message with multiple arguments followed by a newline.
Definition logs.hpp:90
void info_ln(std::string module_name, Types... var2)
Prints a log message with multiple arguments followed by a newline.
Definition logs.hpp:133
void warn_ln(std::string module_name, Types... var2)
Prints a log message with multiple arguments followed by a newline.
Definition logs.hpp:133
sph kernels
Locally isothermal equation of state configuration.
Definition EOSConfig.hpp:61
Configuration struct for the equation of state used in the hydrodynamic models.
Definition EOSConfig.hpp:42
shamphys::EOS_Config_Polytropic< Tscal > Polytropic
Polytropic equation of state configuration.
Definition EOSConfig.hpp:55
shamphys::EOS_Config_Isothermal< Tscal > Isothermal
Isothermal equation of state configuration.
Definition EOSConfig.hpp:58
shamphys::EOS_Config_Fermi< Tscal > Fermi
Fermi equation of state configuration.
Definition EOSConfig.hpp:73
shamphys::EOS_Config_Adiabatic< Tscal > Adiabatic
Adiabatic equation of state configuration.
Definition EOSConfig.hpp:52
The configuration for the CFL condition.
Tscal eta_sink
eta sink to control the sink integrator
Tscal cfl_cour
The CFL condition for the courant factor.
Tscal cfl_multiplier_stiffness
The CFL multiplier stiffness.
Tscal cfl_force
The CFL condition for the force.
std::variant< None, MonofluidTVI, MonofluidComplete > Variant
Variant type to store the EOS configuration.
The configuration for a sph solver.
bool ghost_has_soundspeed()
Whether the ghost cells have a sound speed (i.e. the eos is locally isothermal).
AVConfig artif_viscosity
Configuration for the Artificial Viscosity (AV).
void set_eos_isothermal(Tscal cs)
Set the EOS configuration to an isothermal equation of state.
Tscal gpart_mass
The mass of each gas particle.
u32 h_max_subcycles_count
Maximum number of subcycles before solver crash.
bool compute_luminosity
Whether to store luminosity.
void print_status()
Print the current status of the solver config.
void set_eos_adiabatic(Tscal gamma)
Set the EOS configuration to an adiabatic equation of state.
bool has_field_uint()
Whether the solver has a field for the particle's uint.
bool is_eos_isothermal()
Check if the EOS is an isothermal equation of state.
BCConfig boundary_config
Boundary condition configuration.
bool has_field_psi_on_ch()
Whether the solver has a field for psi_on_ch.
void set_cfl_mult_stiffness(Tscal cstiff)
Set the CFL multiplier for the stiffness.
bool use_two_stage_search
Use two stage neighbors search (see shamrock paper).
Tscal get_cfl_multipler()
Get the CFL multiplier for the time step.
bool has_field_dtdivB()
Whether the solver has a field for dt divB.
bool has_axyz_in_ghost()
Whether the solver has a field for ax, ay, az in ghost cells.
void set_time(Tscal t)
Set the current time.
void set_eos_locally_isothermalLP07(Tscal cs0, Tscal q, Tscal r0)
Set the EOS configuration to a locally isothermal equation of state from Lodato Price 2007.
CFLConfig< Tscal > cfl_config
The configuration for the CFL condition.
bool has_field_divB()
Whether the solver has a field for divB.
Tscal get_time()
Get the current time.
void set_artif_viscosity_VaryingMM97(typename AVConfig::VaryingMM97 v)
Set the artificial viscosity configuration to a varying value using the prescription of Monaghan & Gi...
SolverStatusVar< Tvec > SolverStatusVar
Alias to SolverStatusVar type.
Tscal epsilon_h
Convergence criteria for the smoothing length.
SPHKernel< Tscal > Kernel
The type of the kernel used for the SPH interactions.
bool has_field_curlB()
Whether the solver has a field for curlB.
void add_ext_force_point_mass(Tscal central_mass, Tscal Racc)
Add a point mass external force.
bool do_debug_dump
Whether to dump debug information to file.
bool has_field_divv()
Whether the solver has a field for divv.
shambase::VecComponent< Tvec > Tscal
The type of the scalar used to represent the quantities.
Tscal get_cfl_mult_stiffness()
Get the CFL multiplier for the stiffness.
bool has_field_alphaAV()
Whether the solver has a field for alpha AV.
void set_debug_dump(bool _do_debug_dump, std::string _debug_dump_filename)
Set whether to dump debug information to file.
u32 h_iter_per_subcycles
Maximum number of iterations per subcycle.
shammodels::ExtForceConfig< Tvec > ExtForceConfig
External force configuration.
bool is_eos_adiabatic()
Check if the EOS is an adiabatic equation of state.
void set_artif_viscosity_VaryingCD10(typename AVConfig::VaryingCD10 v)
Set the artificial viscosity configuration to a varying value using the prescription of Cullen & Dehn...
void set_two_stage_search(bool enable)
Setter for the two stage search.
void set_boundary_free()
Set the boundary condition to free boundary.
SolverStatusVar time_state
The time sate of the simulation.
bool has_field_curlv()
Whether the solver has a field for curlv.
bool has_field_dtdivv()
Whether the solver has a field for dt divv.
std::string debug_dump_filename
The filename to dump debug information in.
void add_ext_force_paczynski_wiita(Tscal central_mass, Tvec central_pos, Tscal Racc)
Add a post-newtonian Paczynski-Wiita potential.
bool is_eos_locally_isothermal()
Check if the EOS is a locally isothermal equation of state.
static constexpr Tscal Rkern
The radius of the sph kernel.
void set_eos_locally_isothermalFA2014_extended(Tscal cs0, Tscal q, Tscal r0, u32 n_sinks)
Set the EOS configuration to a locally isothermal equation of state from Farris 2014 extended to q !...
void set_eos_locally_isothermal()
Set the EOS configuration to a locally isothermal equation of state.
Tscal get_constant_G()
Retrieves the value of the constant G based on the unit system.
void set_eos_locally_isothermalFA2014(Tscal h_over_r)
Set the EOS configuration to a locally isothermal equation of state fromFarris 2014.
u32 u_morton
The type of the Morton code for the tree.
Tscal get_constant_mu_0()
Retrieves the value of the constant mu_0 based on the unit system.
void set_units(shamunits::UnitSystem< Tscal > new_sys)
Set the unit system of the simulation.
void set_artif_viscosity_None()
Set the artificial viscosity configuration to None.
bool is_eos_fermi()
Check if the EOS is a Fermi equation of state.
Tscal get_dt_sph()
Get the time step for the next iteration.
void set_IdealMHD(typename MHDConfig::IdealMHD_constrained_hyper_para v)
Enable the ideal MHD hydro solver.
void set_tree_reduction_level(u32 level)
Setter for the tree reduction level.
static constexpr u32 dim
The dimension of the problem.
void set_eos_polytropic(Tscal K, Tscal gamma)
Set the EOS configuration to an polytropic equation of state.
Tscal get_constant_c()
Retrieves the value of the constant c based on the unit system.
void set_artif_viscosity_Constant(typename AVConfig::Constant v)
Set the artificial viscosity configuration to a constant value.
bool is_eos_polytropic()
Check if the EOS is a polytropic equation of state.
AVConfig< Tvec > AVConfig
Configuration for the Artificial Viscosity (AV).
BCConfig< Tvec > BCConfig
Configuration of the boundary conditions.
void set_boundary_shearing_periodic(i32_3 shear_base, i32_3 shear_dir, Tscal speed)
Set the boundary condition to shearing periodic boundary.
Tscal htol_up_fine_cycle
Maximum factor of the smoothing length evolution per subcycles.
void set_boundary_periodic()
Set the boundary condition to periodic boundary.
u32 tree_reduction_level
Reduction level to be used in the tree build.
bool has_field_B_on_rho()
Whether the solver has a field for B_on_rho.
constexpr bool do_MHD_debug()
Whether to add debug fields to the pdl.
std::optional< shamunits::UnitSystem< Tscal > > unit_sys
The unit system of the simulation.
EOSConfig eos_config
EOS configuration.
shammodels::EOSConfig< Tvec > EOSConfig
Alias to EOSConfig type.
bool has_field_soundspeed()
Whether the solver has a field for sound speed.
void set_noMHD()
disable MHD in the SPH solver
void set_next_dt(Tscal dt)
Set the time step for the next iteration.
ExtForceConfig ext_force_config
External force configuration.
void add_ext_force_shearing_box(Tscal Omega_0, Tscal eta, Tscal q)
Add a shearing box external force.
void set_artif_viscosity_ConstantDisc(typename AVConfig::ConstantDisc v)
Set the artificial viscosity configuration to a constant value in the disc plane.
void add_ext_force_lense_thirring(Tscal central_mass, Tscal Racc, Tscal a_spin, Tvec dir_spin)
Add a Lense-Thirring external force.
void set_cfl_multipler(Tscal lambda)
Set the CFL multiplier for the time step.
void set_eos_fermi(Tscal mu_e)
Set the EOS configuration to a Fermi equation of state.
Solver status variables.
Tscal dt_sph
Current time step.
Tscal cfl_multiplier
Current cfl multiplier.
shambase::VecComponent< Tvec > Tscal
The type of the scalar used to represent the quantities.
Physical constants.
constexpr T c()
get c in the current unit system units (m.s-1)
constexpr T G()
get the value of G in the current unit system units
constexpr T mu_0()
get the value of mu_0 in the current unit system units
Functions related to the MPI communicator.
#define ON_RANK_0(x)
Macro to execute code only on rank 0.
Definition worldInfo.hpp:73