50 inline f64 rate_sum() {
return shamalgs::collective::allreduce_sum(rate); }
52 inline u64 npart_sum() {
return shamalgs::collective::allreduce_sum(npart); }
54 inline f64 tcompute_max() {
return shamalgs::collective::allreduce_max(tcompute); }
58 bool reach_target_time;
60 bool reach_max_walltime;
69 struct WalltimeLimiter {
75 inline WalltimeLimiter(
bool active,
f64 max_walltime)
76 : active(active), max_walltime(max_walltime) {
77 start_wall_time = active ? synced_wtime() : 0;
78 next_check_iter = active ? 1 : std::numeric_limits<i32>::max();
81 inline f64 synced_wtime() {
89 inline bool due(
i32 iter_count)
const {
return active && iter_count >= next_check_iter; }
94 f64 global_walltime = synced_wtime();
97 if (global_walltime >= max_walltime) {
102 "stopping evolve until because of "
103 "max_walltime = {:.2f}s > {:.2f}s",
110 f64 sec_per_iter = (global_walltime - start_wall_time) /
static_cast<f64>(iter_count);
112 auto get_remaining_iters = [&](
f64 delta_walltime,
f64 factor) ->
i32 {
113 if (sec_per_iter > 0) {
114 f64 tmp = factor * delta_walltime / sec_per_iter;
115 if (tmp > std::numeric_limits<i32>::max()) {
116 return std::numeric_limits<i32>::max();
118 return static_cast<i32>(tmp);
123 i32 iters_to_limit = get_remaining_iters(max_walltime - global_walltime, 0.25);
124 i32 iters_to_next_check = iters_to_limit;
126 next_check_iter = iter_count + std::max(1, iters_to_next_check);
132 "next walltime check in {:.2f}s (niter = {}) global walltime = "
133 "{:.2f}s (max_walltime = {:.2f}s)",
134 iters_to_next_check * sec_per_iter,
150 template<
class Tvec,
template<
class>
class SPHKernel>
153 using Tscal = shambase::VecComponent<Tvec>;
154 static constexpr u32 dim = shambase::VectorProperties<Tvec>::dimension;
155 using Kernel = SPHKernel<Tscal>;
161 static constexpr Tscal Rkern = Kernel::Rkern;
168 Config solver_config;
175 .template get_edge_ref<shamrock::solvergraph::IDataEdgeSerializable<Tscal>>(
"time")
183 .template get_edge_ref<shamrock::solvergraph::IDataEdgeSerializable<Tscal>>(
"dt")
191 .template get_edge_ref<shamrock::solvergraph::IDataEdgeSerializable<Tscal>>(
205 auto &sync = scheduler().synchronized_data;
206 auto names = sync.get_edge_names();
207 auto has_edge = [&](
const std::string &name) {
208 return std::find(names.begin(), names.end(), name) != names.end();
211 if (!has_edge(
"time")) {
212 auto edge = sync.register_edge(
216 if (!has_edge(
"dt")) {
217 auto edge = sync.register_edge(
221 if (!has_edge(
"cfl_multiplier")) {
222 auto edge = sync.register_edge(
225 "cfl_multiplier",
"C_{\\rm CFL}"));
231 std::optional<std::function<void(
void)>> step_begin_callback;
232 std::optional<std::function<void(
void)>> step_end_callback;
234 std::vector<SolverStepCallback> timestep_callbacks{};
236 inline void init_required_fields() { solver_config.set_layout(context.get_pdl_write()); }
239 void gen_serial_patch_tree();
240 inline void reset_serial_patch_tree() { storage.serial_patch_tree.reset(); }
243 using GhostHandle = sph::BasicSPHGhostHandler<Tvec>;
244 using GhostHandleCache =
typename GhostHandle::CacheMap;
246 inline void gen_ghost_handler(Tscal time_val) {
248 using CfgClass = sph::BasicSPHGhostHandlerConfig<Tvec>;
249 using BCConfig =
typename CfgClass::Variant;
251 using BCFree =
typename CfgClass::Free;
252 using BCPeriodic =
typename CfgClass::Periodic;
253 using BCShearingPeriodic =
typename CfgClass::ShearingPeriodic;
256 using SolverBCFree =
typename SolverConfigBC::Free;
257 using SolverBCPeriodic =
typename SolverConfigBC::Periodic;
258 using SolverBCShearingPeriodic =
typename SolverConfigBC::ShearingPeriodic;
263 storage.ghost_handler.set(
267 storage.patch_rank_owner,
268 storage.xyzh_ghost_layout});
271 = std::get_if<SolverBCPeriodic>(&solver_config.boundary_config.config)) {
272 storage.ghost_handler.set(
276 storage.patch_rank_owner,
277 storage.xyzh_ghost_layout});
279 SolverBCShearingPeriodic *c
280 = std::get_if<SolverBCShearingPeriodic>(&solver_config.boundary_config.config)) {
281 storage.ghost_handler.set(
285 c->shear_base, c->shear_dir, c->shear_speed * time_val, c->shear_speed},
286 storage.patch_rank_owner,
287 storage.xyzh_ghost_layout});
290 inline void reset_ghost_handler() { storage.ghost_handler.reset(); }
301 using RTree =
typename Config::RTree;
355 Solver(ShamrockCtx &context) : context(context) {}
361 void vtk_do_dump(std::string filename,
bool add_patch_world_id);
363 void set_debug_dump(
bool _do_debug_dump, std::string _debug_dump_filename) {
364 solver_config.set_debug_dump(_do_debug_dump, _debug_dump_filename);
367 inline void print_timestep_logs() {
369 logger::info_ln(
"SPH",
"iteration since start :", solve_logs.get_iteration_count());
370 logger::info_ln(
"SPH",
"time since start :", shambase::details::get_wtime(),
"(s)");
380 set_next_dt(dt_input);
386 Tscal target_time,
i32 niter_max,
f64 max_walltime = -1) {
388 const bool niter_limit_active = (niter_max >= 0);
389 const bool walltime_limit_active = (max_walltime >= 0);
395 "evolve_until (target_time = {:.2f}s, niter_max = {}, max_walltime = "
403 Tscal dt = get_dt_sph();
404 Tscal t = get_time();
406 if (t > target_time) {
408 "the target time is higher than the current time");
411 if (t + dt > target_time) {
412 set_next_dt(target_time - t);
417 WalltimeLimiter walltime_limiter(walltime_limit_active, max_walltime);
421 while (get_time() < target_time) {
426 if (niter_limit_active && iter_count >= niter_max) {
429 "SPH",
"stopping evolve until because of niter =", iter_count);
432 .reach_target_time =
false,
433 .reach_niter_max =
true,
434 .reach_max_walltime =
false,
435 .iter_count = iter_count,
440 if (walltime_limiter.due(iter_count)) {
442 if (walltime_limiter.exceeded(iter_count)) {
444 .reach_target_time =
false,
445 .reach_niter_max =
false,
446 .reach_max_walltime =
true,
447 .iter_count = iter_count,
453 print_timestep_logs();
456 .reach_target_time =
true,
457 .reach_niter_max =
false,
458 .reach_max_walltime =
false,
459 .iter_count = iter_count,
double f64
Alias for double.
std::uint32_t u32
32 bit unsigned integer
std::uint64_t u64
64 bit unsigned integer
std::int32_t i32
32 bit integer
void reset_presteps_rint()
Resets tree radius interval field.
void ensure_time_state_edges()
Register time/dt/cfl_multiplier synchronized edges if missing (idempotent).
void reset_merge_ghosts_fields()
Resets merged ghost field data.
void update_sync_load_values()
Updates load balancing values and synchronizes patch ownership.
Tscal & cfl_multiplier_edge_value()
Access synchronized CFL multiplier (scheduler edge "cfl_multiplier").
bool apply_corrector(Tscal dt, u64 Npart_all)
void merge_position_ghost()
Merges ghost particle positions from neighboring patches.
void reset_eos_fields()
Frees memory allocated for EOS fields.
void prepare_corrector()
Saves old derivative fields for predictor-corrector integration.
void build_ghost_cache()
Builds ghost particle interface cache for inter-patch communication.
void update_artificial_viscosity(Tscal dt)
Updates artificial viscosity coefficients for shock capturing.
TimestepLog evolve_once()
Performs one complete SPH timestep evolution.
void vtk_do_dump(std::string filename, bool add_patch_world_id)
Writes VTK dump file for visualization.
void update_derivs(Tscal dt_hydro)
Updates time derivatives and applies external forces.
void build_merged_pos_trees()
Builds spatial BVH trees for merged positions including ghosts.
void clear_merged_pos_trees()
Clears merged position trees to free memory.
void init_solver_graph()
Initializes the solver graph for computation pipeline.
void sph_prestep(Tscal time_val, Tscal dt)
Performs pre-step operations for SPH timestep.
void compute_presteps_rint()
Computes maximum smoothing length in tree nodes for neighbor search.
void compute_eos_fields()
Computes equation of state fields (pressure, sound speed).
void apply_position_boundary(Tscal time_val)
Applies position-based boundary conditions.
void reset_neighbors_cache()
Resets neighbor cache.
Tscal evolve_once_time_expl(Tscal t_current, Tscal dt_input)
Evolves system by one explicit timestep with specified time and dt.
Tscal & dt_edge_value()
Access synchronized next dt (scheduler edge "dt", not solver_graph "dt").
void communicate_merge_ghosts_fields()
Communicates and merges ghost particle fields across processes.
void clear_ghost_cache()
Clears ghost particle cache to free memory.
void init_ghost_layout()
Initializes data layout for ghost particle fields.
void start_neighbors_cache()
Builds neighbor particle cache for SPH calculations.
Tscal & time_edge_value()
Access synchronized simulation time (scheduler edge "time").
This header file contains utility functions related to exception handling in the code.
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...
ExcptTypes make_except_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Create an exception with a message and a location.
i32 world_rank()
Gives the rank of the current process in the MPI communicator.
namespace for the sph model
void info_ln(std::string module_name, Types... var2)
Prints a log message with multiple arguments followed by a newline.
f64 get_wtime()
Returns the current wall clock time in seconds.
Class holding the logs of the solver /todo add a variable to keep only a definite number of steps in ...
The configuration for a sph solver.
BCConfig boundary_config
Boundary condition configuration.
u32 u_morton
The type of the Morton code for the tree.
BCConfig< Tvec > BCConfig
Configuration of the boundary conditions.
bool due(i32 iter_count) const
True if the next walltime check is due at this iteration count.
bool exceeded(i32 iter_count)