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 Tscal>
67 struct CFLConfig {
68
72 Tscal cfl_cour;
73
77 Tscal cfl_force;
78
83
85 Tscal eta_sink = 0.05;
86 };
87
88 template<class Tvec>
90 using Tscal = shambase::VecComponent<Tvec>;
91 struct Sphere {
92 Tvec center;
93 Tscal radius;
94 };
95
96 using kill_t = std::variant<Sphere>;
97
98 std::vector<kill_t> kill_list;
99
100 inline void add_kill_sphere(const Tvec &center, Tscal radius) {
101 kill_list.push_back(Sphere{center, radius});
102 }
103 };
104
105 template<class Tscal>
106 struct DustConfig {
107
108 struct None {};
109
111 u32 ndust;
112 bool pure_diffusion_mode = false;
113
114 Tscal C_1_fluid = 0.1;
115 Tscal C_drift = 1.0;
116 Tscal cfl_density_threshold = shambase::get_epsilon<Tscal>();
117
118 bool ensure_s_j_positivity = true;
119
120 bool smooth_s_positivity_limiter = false;
121
122 // use the corrected q_AV from Hutchison 2018 & Price Laibe 15
123 bool dust_corrected_av = false;
124 };
125
127 u32 ndust;
128 };
129
131 using Variant = std::variant<None, MonofluidTVA, MonofluidComplete>;
132
133 Variant current_mode = None{};
134
135 inline void set_none() { current_mode = None{}; }
136 inline void set_monofluid_tva(
137 u32 nvar,
138 bool pure_diffusion_mode = false,
139 Tscal C_1_fluid = 0.1,
140 Tscal C_drift = 1.0,
141 Tscal cfl_density_threshold = shambase::get_epsilon<Tscal>(),
142 bool ensure_s_j_positivity = true,
143 bool smooth_s_positivity_limiter = false,
144 bool dust_corrected_av = false) {
145 current_mode = MonofluidTVA{
146 nvar,
147 pure_diffusion_mode,
148 C_1_fluid,
149 C_drift,
150 cfl_density_threshold,
151 ensure_s_j_positivity,
152 smooth_s_positivity_limiter,
153 dust_corrected_av};
154 }
155 inline void set_monofluid_complete(u32 nvar) { current_mode = MonofluidComplete{nvar}; }
156
157 inline bool is_none() { return std::holds_alternative<None>(current_mode); }
158 inline bool is_monofluid_tva() { return bool(std::get_if<MonofluidTVA>(&current_mode)); }
159 inline bool is_monofluid_complete() {
160 return bool(std::get_if<MonofluidComplete>(&current_mode));
161 }
162
163 inline MonofluidTVA &get_monofluid_tva() {
164 return shambase::get_check_ref(std::get_if<MonofluidTVA>(&current_mode));
165 }
166
167 inline void mode_to_json(nlohmann::json &j) const {
168 if (const None *cfg = std::get_if<None>(&current_mode)) {
169 j = {{"type", "none"}};
170 } else if (const MonofluidTVA *cfg = std::get_if<MonofluidTVA>(&current_mode)) {
171 j
172 = {{"type", "monofluid_tva"},
173 {"ndust", cfg->ndust},
174 {"pure_diffusion_mode", cfg->pure_diffusion_mode},
175 {"C_1_fluid", cfg->C_1_fluid},
176 {"C_drift", cfg->C_drift},
177 {"cfl_density_threshold", cfg->cfl_density_threshold},
178 {"ensure_s_j_positivity", cfg->ensure_s_j_positivity},
179 {"smooth_s_positivity_limiter", cfg->smooth_s_positivity_limiter},
180 {"dust_corrected_av", cfg->dust_corrected_av}};
181 } else if (
182 const MonofluidComplete *cfg = std::get_if<MonofluidComplete>(&current_mode)) {
183 j = {{"type", "monofluid_complete"}, {"ndust", cfg->ndust}};
184 } else {
186 }
187 }
188
189 inline void mode_from_json(const nlohmann::json &j) {
190 const std::string type = j.at("type").get<std::string>();
191 if (type == "none") {
192 set_none();
193 } else if (type == "monofluid_tva") {
194 set_monofluid_tva(
195 j.at("ndust").get<u32>(),
196 j.at("pure_diffusion_mode").get<bool>(),
197 j.at("C_1_fluid").get<Tscal>(),
198 j.at("C_drift").get<Tscal>(),
199 j.at("cfl_density_threshold").get<Tscal>(),
200 j.at("ensure_s_j_positivity").get<bool>(),
201 j.value("smooth_s_positivity_limiter", false),
202 j.value("dust_corrected_av", false));
203 } else if (type == "monofluid_complete") {
204 set_monofluid_complete(j.at("ndust").get<u32>());
205 } else {
207 }
208 }
209
210 inline bool has_s_j_field() {
211 return is_monofluid_tva(); // S_j = sqrt(\rho \epsilon_j)
212 }
213
214 inline bool should_use_dust_av() {
215 if (!is_monofluid_tva()) {
216 return false;
217 }
218 return get_monofluid_tva().dust_corrected_av;
219 }
220
221 inline bool has_epsilon_field() {
222 return bool(std::get_if<MonofluidComplete>(&current_mode));
223 }
224
225 inline bool has_deltav_field() {
226 return bool(std::get_if<MonofluidComplete>(&current_mode));
227 }
228
229 inline u32 get_dust_nvar() {
230 if (None *cfg = std::get_if<None>(&current_mode)) {
232 "Querying a dust nvar with no dust as config is ... discutable ...");
233 return 0;
234 } else if (MonofluidTVA *cfg = std::get_if<MonofluidTVA>(&current_mode)) {
235 return cfg->ndust;
236 } else if (MonofluidComplete *cfg = std::get_if<MonofluidComplete>(&current_mode)) {
237 return cfg->ndust;
238 } else {
239 shambase::throw_unimplemented("How did you get here ???");
240 }
241 return 0;
242 }
243
245 std::vector<Tscal> stopping_times;
246 };
247
248 struct EpsteinDrag {
249 static constexpr bool supersonic_correction = false;
250 Tscal gamma;
251 std::vector<Tscal> grains_sizes;
252 std::vector<Tscal> grains_densities;
253 };
254
255 std::variant<None, ConstantStoppingTimes, EpsteinDrag> dust_drag_mode = None{};
256
257 bool ballabio_ts_limiter = false;
258
259 inline void drag_mode_to_json(nlohmann::json &j) const {
260 if (std::holds_alternative<None>(dust_drag_mode)) {
261 j = {{"type", "none"}};
262 } else if (
263 const ConstantStoppingTimes *cfg
264 = std::get_if<ConstantStoppingTimes>(&dust_drag_mode)) {
265 j = {{"type", "constant_stopping_times"}, {"stopping_times", cfg->stopping_times}};
266 } else if (const EpsteinDrag *cfg = std::get_if<EpsteinDrag>(&dust_drag_mode)) {
267 j
268 = {{"type", "epstein_drag"},
269 {"gamma", cfg->gamma},
270 {"grains_sizes", cfg->grains_sizes},
271 {"grains_densities", cfg->grains_densities}};
272 } else {
274 }
275 }
276
277 inline void drag_mode_from_json(const nlohmann::json &j) {
278 if (j.at("type").get<std::string>() == "none") {
279 dust_drag_mode = None{};
280 } else if (j.at("type").get<std::string>() == "constant_stopping_times") {
281 dust_drag_mode
282 = ConstantStoppingTimes{j.at("stopping_times").get<std::vector<Tscal>>()};
283 } else if (j.at("type").get<std::string>() == "epstein_drag") {
284 dust_drag_mode = EpsteinDrag{
285 j.at("gamma").get<Tscal>(),
286 j.at("grains_sizes").get<std::vector<Tscal>>(),
287 j.at("grains_densities").get<std::vector<Tscal>>()};
288 } else {
290 }
291 }
292
293 inline void set_drag_constant(ConstantStoppingTimes in) { dust_drag_mode = std::move(in); }
294
295 inline void set_drag_epstein(EpsteinDrag in) { dust_drag_mode = std::move(in); }
296
297 inline void check_config() {
298 bool is_not_none = !is_none();
299 if (is_not_none) {
300
303 "Dust config != None is experimental");
304 } else {
305 ON_RANK_0(
306 logger::warn_ln(
307 "SPH::config",
308 "Dust config != None is work in progress, use it at your own risk"));
309 }
310
311 if (std::holds_alternative<None>(dust_drag_mode)) {
313 "you must select a drag mode for the dust if the dust is on !");
314 } else if (
316 = std::get_if<ConstantStoppingTimes>(&dust_drag_mode)) {
317 if (get_dust_nvar() != cfg->stopping_times.size()) {
319 "stopping_times size does not match the number of dust bins");
320 }
321 } else if (EpsteinDrag *cfg = std::get_if<EpsteinDrag>(&dust_drag_mode)) {
322 if (get_dust_nvar() != cfg->grains_densities.size()) {
324 "grains_densities size does not match the number of dust bins");
325 }
326
327 if (get_dust_nvar() != cfg->grains_sizes.size()) {
329 "grains_sizes size does not match the number of dust bins");
330 }
331 }
332 }
333 }
334 };
335
337 struct DensityBased {};
339 u32 max_neigh_count = 500;
340 };
341
342 using mode = std::variant<DensityBased, DensityBasedNeighLim>;
343
344 mode config = DensityBased{};
345
346 void set_density_based() { config = DensityBased{}; }
347 void set_density_based_neigh_lim(u32 max_neigh_count) {
348 config = DensityBasedNeighLim{max_neigh_count};
349 }
350
351 bool is_density_based_neigh_lim() const {
352 return std::holds_alternative<DensityBasedNeighLim>(config);
353 }
354 };
355
357
358 struct SFMM {
359 u32 order;
360 f64 opening_angle;
361 bool leaf_lowering;
362 u32 reduction_level;
363 };
364
365 struct FMM {
366 u32 order;
367 f64 opening_angle;
368 u32 reduction_level;
369 };
370
371 struct MM {
372 u32 order;
373 f64 opening_angle;
374 u32 reduction_level;
375 };
376
377 struct Direct {
378 bool reference_mode = false;
379 };
380
381 struct None {};
382
383 using mode = std::variant<SFMM, FMM, MM, Direct, None>;
384
385 mode config = None{};
386
387 void set_none() { config = None{}; }
388 void set_direct(bool reference_mode = false) { config = Direct{reference_mode}; }
389 void set_mm(u32 mm_order, f64 opening_angle, u32 reduction_level) {
390 config = MM{
391 .order = mm_order,
392 .opening_angle = opening_angle,
393 .reduction_level = reduction_level};
394 }
395 void set_fmm(u32 order, f64 opening_angle, u32 reduction_level) {
396 config = FMM{
397 .order = order, .opening_angle = opening_angle, .reduction_level = reduction_level};
398 }
399 void set_sfmm(u32 order, f64 opening_angle, bool leaf_lowering, u32 reduction_level) {
400 config = SFMM{
401 .order = order,
402 .opening_angle = opening_angle,
403 .leaf_lowering = leaf_lowering,
404 .reduction_level = reduction_level};
405 }
406
407 bool is_none() const { return std::holds_alternative<None>(config); }
408 bool is_direct() const { return std::holds_alternative<Direct>(config); }
409 bool is_mm() const { return std::holds_alternative<MM>(config); }
410 bool is_fmm() const { return std::holds_alternative<FMM>(config); }
411 bool is_sfmm() const { return std::holds_alternative<SFMM>(config); }
412
413 bool is_sg_on() const { return !is_none(); }
414 bool is_sg_off() const { return is_none(); }
415
417 f64 epsilon;
418 };
419
420 using mode_soft = std::variant<SofteningPlummer>;
421 mode_soft softening_mode = SofteningPlummer{1e-9};
422
423 void set_softening_plummer(f64 epsilon) { softening_mode = SofteningPlummer{epsilon}; }
424 void set_softening_none() { set_softening_plummer(0.); }
425
426 bool is_softening_plummer() const {
427 return std::holds_alternative<SofteningPlummer>(softening_mode);
428 }
429 };
430
431} // namespace shammodels::sph
432
433template<class Tvec, template<class> class SPHKernel>
435
437 using Tscal = shambase::VecComponent<Tvec>;
439 static constexpr u32 dim = shambase::VectorProperties<Tvec>::dimension;
441 using Kernel = SPHKernel<Tscal>;
443 using u_morton = u32;
444
446
448 static constexpr Tscal Rkern = Kernel::Rkern;
449
451
452 bool track_particles_id = false;
453
454 inline void set_particle_tracking(bool state) { track_particles_id = state; }
455
456 PatchSchedulerConfig scheduler_conf = {};
457
459 // Units Config
461
463 std::optional<shamunits::UnitSystem<Tscal>> unit_sys = {};
464
466 inline void set_units(shamunits::UnitSystem<Tscal> new_sys) { unit_sys = new_sys; }
467
470 if (!unit_sys) {
471 ON_RANK_0(logger::warn_ln("sph::Config", "the unit system is not set"));
473 return ctes.G();
474 } else {
476 }
477 }
478
481 if (!unit_sys) {
482 ON_RANK_0(logger::warn_ln("sph::Config", "the unit system is not set"));
484 return ctes.c();
485 } else {
487 }
488 }
489
492 if (!unit_sys) {
493 ON_RANK_0(logger::warn_ln("sph::Config", "the unit system is not set"));
495 return ctes.mu_0();
496 } else {
498 }
499 }
500
502 // Units Config (END)
504
506 // Particle killing config
508
509 ParticleKillingConfig<Tvec> particle_killing;
510
512 // Particle killing config (END)
514
516 // CFL Configuration (config)
518
520
522 inline void set_cfl_mult_stiffness(Tscal cstiff) {
523 cfl_config.cfl_multiplier_stiffness = cstiff;
524 }
525
527 inline Tscal get_cfl_mult_stiffness() { return cfl_config.cfl_multiplier_stiffness; }
528
529 bool show_cfl_detail = false;
530
532 // CFL Configuration (END)
534
536 // MHD Config
538
540 MHDConfig mhd_config = {};
541
543 inline void set_noMHD() {
544 using Tmp = typename MHDConfig::None;
545 mhd_config.set(Tmp{});
546 }
547
550 mhd_config.set(v);
551 }
552
553 inline void set_NonIdealMHD(typename MHDConfig::NonIdealMHD v) { mhd_config.set(v); }
554
556 // MHD Config (END)
558
560 // Dust config
562
563 using DustConfig = DustConfig<Tscal>;
564 DustConfig dust_config = {};
565
567 // Dust config (END)
569
571 // Self gravity config
573
574 SelfGravConfig self_grav_config = SelfGravConfig{};
575
577 // Self gravity config (END)
579
581 // Tree config
583
586
588 inline void set_tree_reduction_level(u32 level) { tree_reduction_level = level; }
590 inline void set_two_stage_search(bool enable) { use_two_stage_search = enable; }
591
592 bool show_neigh_stats = false;
593 inline void set_show_neigh_stats(bool enable) { show_neigh_stats = enable; }
595 // Tree config (END)
597
599 // Solver behavior config
601
611
612 SmoothingLengthConfig smoothing_length_config;
613
614 inline void set_smoothing_length_density_based() {
615 smoothing_length_config.set_density_based();
616 }
617 inline void set_smoothing_length_density_based_neigh_lim(u32 max_neigh_count) {
618 smoothing_length_config.set_density_based_neigh_lim(max_neigh_count);
619 }
620
621 bool enable_particle_reordering = false;
622 inline void set_enable_particle_reordering(bool enable) { enable_particle_reordering = enable; }
623 u64 particle_reordering_step_freq = 1000;
624 inline void set_particle_reordering_step_freq(u64 freq) {
625 if (freq == 0) {
627 "particle_reordering_step_freq cannot be zero");
628 }
629 particle_reordering_step_freq = freq;
630 }
631
632 bool save_dt_to_fields = false;
633 inline void set_save_dt_to_fields(bool enable) { save_dt_to_fields = enable; }
634 inline bool should_save_dt_to_fields() const { return save_dt_to_fields; }
635
636 bool show_ghost_zone_graph = false;
637 inline void set_show_ghost_zone_graph(bool enable) { show_ghost_zone_graph = enable; }
638
640 // Solver behavior config (END)
642
644 // EOS Config
646
649
652
655 using T = typename EOSConfig::LocallyIsothermal;
656 return bool(std::get_if<T>(&eos_config.config));
657 }
658
660 inline bool is_eos_adiabatic() {
661 using T = typename EOSConfig::Adiabatic;
662 return bool(std::get_if<T>(&eos_config.config));
663 }
664
666 inline bool is_eos_polytropic() {
667 using T = typename EOSConfig::Polytropic;
668 return bool(std::get_if<T>(&eos_config.config));
669 }
670
672 inline bool is_eos_isothermal() {
673 using T = typename EOSConfig::Isothermal;
674 return bool(std::get_if<T>(&eos_config.config));
675 }
676
678 inline bool is_eos_fermi() {
679 using T = typename EOSConfig::Fermi;
680 return bool(std::get_if<T>(&eos_config.config));
681 }
682
688 inline void set_eos_isothermal(Tscal cs) { eos_config.set_isothermal(cs); }
689
695 inline void set_eos_adiabatic(Tscal gamma) { eos_config.set_adiabatic(gamma); }
696
702 inline void set_eos_polytropic(Tscal K, Tscal gamma) { eos_config.set_polytropic(K, gamma); }
703
707 inline void set_eos_locally_isothermal() { eos_config.set_locally_isothermal(); }
708
718 eos_config.set_locally_isothermalLP07(cs0, q, r0);
719 }
720
729 eos_config.set_locally_isothermalFA2014(h_over_r);
730 }
731
742 Tscal cs0, Tscal q, Tscal r0, u32 n_sinks) {
743 eos_config.set_locally_isothermalFA2014_extended(cs0, q, r0, n_sinks);
744 }
745
751 inline void set_eos_fermi(Tscal mu_e) { eos_config.set_fermi(mu_e); }
752
754 // EOS Config (END)
756
758 // Artificial viscosity Config
760
773
776
781 using Tmp = typename AVConfig::None;
782 artif_viscosity.set(Tmp{});
783 }
784
790 inline void set_artif_viscosity_Constant(typename AVConfig::Constant v) {
791 artif_viscosity.set(v);
792 }
793
800 inline void set_artif_viscosity_VaryingMM97(typename AVConfig::VaryingMM97 v) {
801 artif_viscosity.set(v);
802 }
803
810 inline void set_artif_viscosity_VaryingCD10(typename AVConfig::VaryingCD10 v) {
811 artif_viscosity.set(v);
812 }
813
818 inline void set_artif_viscosity_ConstantDisc(typename AVConfig::ConstantDisc v) {
819 artif_viscosity.set(v);
820 }
821
823 // Artificial viscosity Config (END)
825
827 // Boundary Config
829
834
841
845 inline void set_boundary_free() { boundary_config.set_free(); }
846
850 inline void set_boundary_periodic() { boundary_config.set_periodic(); }
851
863 inline void set_boundary_shearing_periodic(i32_3 shear_base, i32_3 shear_dir, Tscal speed) {
864 boundary_config.set_shearing_periodic(shear_base, shear_dir, speed);
865 }
866
868 // Boundary Config (END)
870
872 // Ext force Config
874
887
892
899 inline void add_ext_force_point_mass(Tscal central_mass, Tscal Racc) {
900 ext_force_config.add_point_mass(central_mass, Racc);
901 }
902
909 inline void add_ext_force_paczynski_wiita(Tscal central_mass, Tvec central_pos, Tscal Racc) {
910 ext_force_config.add_paczynski_wiita(central_mass, central_pos, Racc);
911 }
912
922 Tscal central_mass, Tscal Racc, Tscal a_spin, Tvec dir_spin) {
923 ext_force_config.add_lense_thirring(central_mass, Racc, a_spin, dir_spin);
924 }
925
933 inline void add_ext_force_shearing_box(Tscal Omega_0, Tscal eta, Tscal q) {
934 ext_force_config.add_shearing_box(Omega_0, eta, q);
935 }
936
938 // Ext force Config (END)
940
942 // Debug dump config
944
946 bool do_debug_dump = false;
947
949 std::string debug_dump_filename = "";
950
955 inline void set_debug_dump(bool _do_debug_dump, std::string _debug_dump_filename) {
956 this->do_debug_dump = _do_debug_dump;
957 this->debug_dump_filename = _debug_dump_filename;
958 }
959
961 inline constexpr bool do_MHD_debug() { return false; }
962
964 // Debug dump config (END)
966
969
973 inline bool has_field_uint() {
974 // no barotropic for now
975 return true;
976 }
977
979 inline bool has_field_alphaAV() { return artif_viscosity.has_alphaAV_field(); }
980
982 inline bool has_field_divv() { return artif_viscosity.has_alphaAV_field(); }
983
985 inline bool has_field_dtdivv() { return artif_viscosity.has_dtdivv_field(); }
986
988 inline bool has_field_curlv() { return artif_viscosity.has_curlv_field() && (dim == 3); }
989
991 inline bool has_axyz_in_ghost() { return has_field_dtdivv(); }
992
994 inline bool has_field_soundspeed() {
995 return artif_viscosity.has_field_soundspeed() || is_eos_locally_isothermal();
996 }
997
999 inline bool has_field_B_on_rho() { return mhd_config.has_B_field() && (dim == 3); }
1000
1002 inline bool has_field_psi_on_ch() { return mhd_config.has_psi_field(); }
1003
1005 inline bool has_field_divB() { return mhd_config.has_divB_field(); }
1006
1008 inline bool has_field_curlB() { return mhd_config.has_curlB_field() && (dim == 3); }
1009
1011 inline bool has_field_dtdivB() { return mhd_config.has_dtdivB_field(); }
1012
1015 inline void use_luminosity(bool enable) { compute_luminosity = enable; }
1016
1018 inline void print_status() {
1019 if (shamcomm::world_rank() != 0) {
1020 return;
1021 }
1022 logger::raw_ln("----- SPH Solver configuration -----");
1023 logger::raw_ln(nlohmann::json{*this}.dump(4));
1024 logger::raw_ln("------------------------------------");
1025 }
1026
1027 inline void check_config() {
1028 dust_config.check_config();
1029
1030 if (track_particles_id && false /*particle injection when added*/) {
1032 "particle injection is not yet compatible with particle id tracking");
1033 }
1034
1035 if (track_particles_id) {
1036 shamrock::experimental_feature_check("Particle tracking is experimental");
1037 }
1038
1039 if (!self_grav_config.is_none()) {
1041 "Self gravity is experimental, please enable experimental features to use it");
1042 }
1043 }
1044
1045 void set_layout(shamrock::patch::PatchDataLayerLayout &pdl);
1046 void set_ghost_layout(shamrock::patch::PatchDataLayerLayout &ghost_layout);
1047};
1048
1049namespace shammodels::sph {
1050
1057 template<class Tscal>
1058 inline void to_json(nlohmann::json &j, const CFLConfig<Tscal> &p) {
1059 j = nlohmann::json{
1060 {"cfl_cour", p.cfl_cour},
1061 {"cfl_force", p.cfl_force},
1062 {"cfl_multiplier_stiffness", p.cfl_multiplier_stiffness},
1063 {"eta_sink", p.eta_sink}};
1064 }
1065
1072 template<class Tscal>
1073 inline void from_json(const nlohmann::json &j, CFLConfig<Tscal> &p) {
1074 j.at("cfl_cour").get_to<Tscal>(p.cfl_cour);
1075 j.at("cfl_force").get_to<Tscal>(p.cfl_force);
1076 j.at("cfl_multiplier_stiffness").get_to<Tscal>(p.cfl_multiplier_stiffness);
1077
1078 if (j.contains("eta_sink")) {
1079 j.at("eta_sink").get_to<Tscal>(p.eta_sink);
1080 } else {
1081 // Already set to default value
1082 ON_RANK_0(shamlog_warn_ln(
1083 "SPHConfig", "eta_sink not found when deserializing, defaulting to", p.eta_sink));
1084 }
1085 }
1086
1087 // JSON serialization for ParticleKillingConfig
1088 template<class Tvec>
1089 inline void to_json(nlohmann::json &j, const ParticleKillingConfig<Tvec> &p) {
1090 j = nlohmann::json::array();
1091 for (const auto &kill : p.kill_list) {
1092 if (std::holds_alternative<typename ParticleKillingConfig<Tvec>::Sphere>(kill)) {
1093 const auto &sphere = std::get<typename ParticleKillingConfig<Tvec>::Sphere>(kill);
1094 j.push_back(
1095 {{"type", "sphere"}, {"center", sphere.center}, {"radius", sphere.radius}});
1096 }
1097 // If more types are added to kill_t, handle them here
1098 }
1099 }
1100
1101 template<class Tvec>
1102 inline void from_json(const nlohmann::json &j, ParticleKillingConfig<Tvec> &p) {
1103 p.kill_list.clear();
1104 for (const auto &item : j) {
1105 std::string type = item.at("type").get<std::string>();
1106 if (type == "sphere") {
1108 item.at("center").get_to(sphere.center);
1109 item.at("radius").get_to(sphere.radius);
1110 p.kill_list.push_back(sphere);
1111 }
1112 // If more types are added to kill_t, handle them here
1113 }
1114 }
1115
1116 // JSON serialization for SmoothingLengthConfig
1117 inline void to_json(nlohmann::json &j, const SmoothingLengthConfig &p) {
1119 = std::get_if<SmoothingLengthConfig::DensityBased>(&p.config)) {
1120 j = {
1121 {"type", "density_based"},
1122 };
1123
1124 } else if (
1126 = std::get_if<SmoothingLengthConfig::DensityBasedNeighLim>(&p.config)) {
1127
1128 j = {
1129 {"type", "density_based_neigh_lim"},
1130 {"max_neigh_count", conf->max_neigh_count},
1131 };
1132 } else {
1134 }
1135 }
1136
1137 inline void from_json(const nlohmann::json &j, SmoothingLengthConfig &p) {
1138 if (j.at("type").get<std::string>() == "density_based") {
1140 } else if (j.at("type").get<std::string>() == "density_based_neigh_lim") {
1141 p.config
1142 = SmoothingLengthConfig::DensityBasedNeighLim{j.at("max_neigh_count").get<u32>()};
1143 } else {
1145 }
1146 }
1147
1149 inline void to_json(nlohmann::json &j, const SelfGravConfig &p) {
1150 if (const SelfGravConfig::SFMM *conf = std::get_if<SelfGravConfig::SFMM>(&p.config)) {
1151 j = {
1152 {"type", "sfmm"},
1153 {"order", conf->order},
1154 {"opening_angle", conf->opening_angle},
1155 {"reduction_level", conf->reduction_level},
1156 {"leaf_lowering", conf->leaf_lowering},
1157 };
1158 } else if (const SelfGravConfig::FMM *conf = std::get_if<SelfGravConfig::FMM>(&p.config)) {
1159 j = {
1160 {"type", "fmm"},
1161 {"order", conf->order},
1162 {"opening_angle", conf->opening_angle},
1163 {"reduction_level", conf->reduction_level},
1164 };
1165 } else if (const SelfGravConfig::MM *conf = std::get_if<SelfGravConfig::MM>(&p.config)) {
1166 j = {
1167 {"type", "mm"},
1168 {"order", conf->order},
1169 {"opening_angle", conf->opening_angle},
1170 {"reduction_level", conf->reduction_level},
1171 };
1172 } else if (
1173 const SelfGravConfig::Direct *conf = std::get_if<SelfGravConfig::Direct>(&p.config)) {
1174 j = {
1175 {"type", "direct"},
1176 {"reference_mode", conf->reference_mode},
1177 };
1178 } else if (
1179 const SelfGravConfig::None *conf = std::get_if<SelfGravConfig::None>(&p.config)) {
1180 j = {
1181 {"type", "none"},
1182 };
1183 }
1184
1185 if (const SelfGravConfig::SofteningPlummer *conf
1186 = std::get_if<SelfGravConfig::SofteningPlummer>(&p.softening_mode)) {
1187 j["softening_mode"] = "plummer";
1188 j["softening_length"] = conf->epsilon;
1189 } else {
1191 }
1192 }
1193
1195 inline void from_json(const nlohmann::json &j, SelfGravConfig &p) {
1196 if (j.at("type").get<std::string>() == "sfmm") {
1197 p.config = SelfGravConfig::SFMM{
1198 .order = j.at("order").get<u32>(),
1199 .opening_angle = j.at("opening_angle").get<f64>(),
1200 .leaf_lowering = j.at("leaf_lowering").get<bool>(),
1201 .reduction_level = j.at("reduction_level").get<u32>()};
1202 } else if (j.at("type").get<std::string>() == "fmm") {
1203 p.config = SelfGravConfig::FMM{
1204 .order = j.at("order").get<u32>(),
1205 .opening_angle = j.at("opening_angle").get<f64>(),
1206 .reduction_level = j.at("reduction_level").get<u32>()};
1207 } else if (j.at("type").get<std::string>() == "mm") {
1208 p.config = SelfGravConfig::MM{
1209 .order = j.at("order").get<u32>(),
1210 .opening_angle = j.at("opening_angle").get<f64>(),
1211 .reduction_level = j.at("reduction_level").get<u32>()};
1212 } else if (j.at("type").get<std::string>() == "direct") {
1213 p.config = SelfGravConfig::Direct{j.at("reference_mode").get<bool>()};
1214 } else if (j.at("type").get<std::string>() == "none") {
1215 p.config = SelfGravConfig::None{};
1216 } else {
1218 "Invalid self gravity type: " + j.at("type").get<std::string>());
1219 }
1220
1221 if (j.contains("softening_mode")) {
1222 std::string softening_mode = j.at("softening_mode").get<std::string>();
1223 if (softening_mode == "plummer") {
1224 p.softening_mode
1225 = SelfGravConfig::SofteningPlummer{j.at("softening_length").get<f64>()};
1226 } else {
1228 "Invalid softening mode: " + softening_mode);
1229 }
1230 }
1231 }
1232
1233 // JSON serialization for DustConfig
1234 template<class Tvec>
1235 inline void to_json(nlohmann::json &j, const DustConfig<Tvec> &p) {
1236 j = {};
1237
1238 p.mode_to_json(j["mode"]);
1239 p.drag_mode_to_json(j["drag_mode"]);
1240 j["ballabio_ts_limiter"] = p.ballabio_ts_limiter;
1241 }
1242
1243 template<class Tvec>
1244 inline void from_json(const nlohmann::json &j, DustConfig<Tvec> &p) {
1245 p.mode_from_json(j.at("mode"));
1246 p.drag_mode_from_json(j.at("drag_mode"));
1247 p.ballabio_ts_limiter = j.value("ballabio_ts_limiter", false);
1248 }
1249
1256 template<class Tvec, template<class> class SPHKernel>
1257 inline void to_json(nlohmann::json &j, const SolverConfig<Tvec, SPHKernel> &p) {
1259 using Tkernel = typename T::Kernel;
1260
1261 std::string kernel_id = shambase::get_type_name<Tkernel>();
1262 std::string type_id = shambase::get_type_name<Tvec>();
1263
1264 j = nlohmann::json{
1265 // used for type checking
1266 {"kernel_id", kernel_id},
1267 {"type_id", type_id},
1268 // scheduler config
1269 {"scheduler_config", p.scheduler_conf},
1270 // actual data stored in the json
1271 {"gpart_mass", p.gpart_mass},
1272 {"cfl_config", p.cfl_config},
1273 {"unit_sys", p.unit_sys},
1274 {"show_cfl_detail", p.show_cfl_detail},
1275 // mhd config
1276 {"mhd_config", p.mhd_config},
1277 // dust config
1278 {"dust_config", p.dust_config},
1279 // self gravity config
1280 {"self_grav_config", p.self_grav_config},
1281 // tree config
1282 {"tree_reduction_level", p.tree_reduction_level},
1283 {"use_two_stage_search", p.use_two_stage_search},
1284 {"show_neigh_stats", p.show_neigh_stats},
1285 // solver behavior config
1286 {"combined_dtdiv_divcurlv_compute", p.combined_dtdiv_divcurlv_compute},
1287 {"htol_up_coarse_cycle", p.htol_up_coarse_cycle},
1288 {"htol_up_fine_cycle", p.htol_up_fine_cycle},
1289 {"epsilon_h", p.epsilon_h},
1290 {"smoothing_length_config", p.smoothing_length_config},
1291 {"h_iter_per_subcycles", p.h_iter_per_subcycles},
1292 {"h_max_subcycles_count", p.h_max_subcycles_count},
1293
1294 {"enable_particle_reordering", p.enable_particle_reordering},
1295 {"particle_reordering_step_freq", p.particle_reordering_step_freq},
1296
1297 {"save_dt_to_fields", p.save_dt_to_fields},
1298 {"show_ghost_zone_graph", p.show_ghost_zone_graph},
1299
1300 {"eos_config", p.eos_config},
1301
1302 {"artif_viscosity", p.artif_viscosity},
1303 {"boundary_config", p.boundary_config},
1304 {"ext_force_config", p.ext_force_config},
1305
1306 {"do_debug_dump", p.do_debug_dump},
1307 {"debug_dump_filename", p.debug_dump_filename},
1308 // particle killing config
1309 {"particle_killing", p.particle_killing},
1310 };
1311 }
1312
1319 template<class Tvec, template<class> class SPHKernel>
1320 inline void from_json(const nlohmann::json &j, SolverConfig<Tvec, SPHKernel> &p) {
1322 using Tkernel = typename T::Kernel;
1323
1324 // type checking
1325 if (j.contains("kernel_id")) {
1326
1327 std::string kernel_id = j.at("kernel_id").get<std::string>();
1328
1329 if (kernel_id != shambase::get_type_name<Tkernel>()) {
1331 "Invalid type to deserialize, wanted " + shambase::get_type_name<Tvec>()
1332 + " but got " + kernel_id);
1333 }
1334 }
1335
1336 if (j.contains("type_id")) {
1337
1338 std::string type_id = j.at("type_id").get<std::string>();
1339
1340 if (type_id != shambase::get_type_name<Tvec>()) {
1342 "Invalid type to deserialize, wanted " + shambase::get_type_name<Tvec>()
1343 + " but got " + type_id);
1344 }
1345 }
1346
1347 bool has_used_defaults = false;
1348 bool has_updated_config = false;
1349
1350 auto _get_to_if_contains = [&](const std::string &key, auto &value) {
1351 shamrock::get_to_if_contains(j, key, value, has_used_defaults);
1352 };
1353
1354 auto _get_to_if_contains_fallbacks = [&](const std::string &key,
1355 auto &value,
1356 std::initializer_list<const char *> fallbacks) {
1358 j, key, value, fallbacks, has_used_defaults, has_updated_config);
1359 };
1360
1361 _get_to_if_contains("scheduler_config", p.scheduler_conf);
1362
1363 // actual data stored in the json
1364 _get_to_if_contains("gpart_mass", p.gpart_mass);
1365 _get_to_if_contains("cfl_config", p.cfl_config);
1366 _get_to_if_contains("unit_sys", p.unit_sys);
1367 _get_to_if_contains("show_cfl_detail", p.show_cfl_detail);
1368 _get_to_if_contains("mhd_config", p.mhd_config);
1369 _get_to_if_contains("dust_config", p.dust_config);
1370 _get_to_if_contains("self_grav_config", p.self_grav_config);
1371 _get_to_if_contains("tree_reduction_level", p.tree_reduction_level);
1372 _get_to_if_contains("use_two_stage_search", p.use_two_stage_search);
1373 _get_to_if_contains("show_neigh_stats", p.show_neigh_stats);
1374 _get_to_if_contains("combined_dtdiv_divcurlv_compute", p.combined_dtdiv_divcurlv_compute);
1375
1376 // Try new names first, fall back to old names for backward compatibility
1377 _get_to_if_contains_fallbacks(
1378 "htol_up_coarse_cycle", p.htol_up_coarse_cycle, {"htol_up_tol"});
1379 _get_to_if_contains_fallbacks("htol_up_fine_cycle", p.htol_up_fine_cycle, {"htol_up_iter"});
1380
1381 _get_to_if_contains("epsilon_h", p.epsilon_h);
1382 _get_to_if_contains("smoothing_length_config", p.smoothing_length_config);
1383 _get_to_if_contains("h_iter_per_subcycles", p.h_iter_per_subcycles);
1384 _get_to_if_contains("h_max_subcycles_count", p.h_max_subcycles_count);
1385 _get_to_if_contains("enable_particle_reordering", p.enable_particle_reordering);
1386 _get_to_if_contains("particle_reordering_step_freq", p.particle_reordering_step_freq);
1387 _get_to_if_contains("save_dt_to_fields", p.save_dt_to_fields);
1388 _get_to_if_contains("show_ghost_zone_graph", p.show_ghost_zone_graph);
1389 _get_to_if_contains("eos_config", p.eos_config);
1390 _get_to_if_contains("artif_viscosity", p.artif_viscosity);
1391 _get_to_if_contains("boundary_config", p.boundary_config);
1392 _get_to_if_contains("ext_force_config", p.ext_force_config);
1393 _get_to_if_contains("do_debug_dump", p.do_debug_dump);
1394 _get_to_if_contains("debug_dump_filename", p.debug_dump_filename);
1395 _get_to_if_contains("particle_killing", p.particle_killing);
1396
1397 if (has_used_defaults || has_updated_config) {
1398 if (shamcomm::world_rank() == 0) {
1400 "SPH::SolverConfig",
1401 shamrock::log_json_changes(p, j, has_used_defaults, has_updated_config));
1402 }
1403 }
1404 }
1405
1406} // 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.
T & get_check_ref(const std::unique_ptr< T > &ptr, SourceLocation loc=SourceLocation())
Takes a std::unique_ptr and returns a reference to the object it holds. It throws a std::runtime_erro...
Definition memory.hpp:110
ExcptTypes make_except_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Create an exception with a message and a location.
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, MonofluidTVA, 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).
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_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.
void set_artif_viscosity_VaryingMM97(typename AVConfig::VaryingMM97 v)
Set the artificial viscosity configuration to a varying value using the prescription of Monaghan & Gi...
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.
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.
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
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_eos_fermi(Tscal mu_e)
Set the EOS configuration to a Fermi equation of state.
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