73 using Tscal = shambase::VecComponent<Tvec>;
74 static constexpr u32 dim = shambase::VectorProperties<Tvec>::dimension;
75 using Kernel = SPHKernel<Tscal>;
81 static constexpr Tscal Rkern = Kernel::Rkern;
95 .template get_edge_ref<shamrock::solvergraph::IDataEdgeSerializable<Tscal>>(
"time")
103 .template get_edge_ref<shamrock::solvergraph::IDataEdgeSerializable<Tscal>>(
"dt")
111 .template get_edge_ref<shamrock::solvergraph::IDataEdgeSerializable<Tscal>>(
125 auto &sync = scheduler().synchronized_data;
126 auto names = sync.get_edge_names();
127 auto has_edge = [&](
const std::string &name) {
128 return std::find(names.begin(), names.end(), name) != names.end();
131 if (!has_edge(
"time")) {
132 auto edge = sync.register_edge(
136 if (!has_edge(
"dt")) {
137 auto edge = sync.register_edge(
141 if (!has_edge(
"cfl_multiplier")) {
142 auto edge = sync.register_edge(
145 "cfl_multiplier",
"C_{\\rm CFL}"));
151 std::optional<std::function<void(
void)>> step_begin_callback;
152 std::optional<std::function<void(
void)>> step_end_callback;
154 std::vector<SolverStepCallback> timestep_callbacks{};
156 inline void init_required_fields() { solver_config.set_layout(context.get_pdl_write()); }
159 void gen_serial_patch_tree();
160 inline void reset_serial_patch_tree() { storage.serial_patch_tree.reset(); }
163 using GhostHandle = sph::BasicSPHGhostHandler<Tvec>;
164 using GhostHandleCache =
typename GhostHandle::CacheMap;
166 inline void gen_ghost_handler(Tscal time_val) {
168 using CfgClass = sph::BasicSPHGhostHandlerConfig<Tvec>;
169 using BCConfig =
typename CfgClass::Variant;
171 using BCFree =
typename CfgClass::Free;
172 using BCPeriodic =
typename CfgClass::Periodic;
173 using BCShearingPeriodic =
typename CfgClass::ShearingPeriodic;
176 using SolverBCFree =
typename SolverConfigBC::Free;
177 using SolverBCPeriodic =
typename SolverConfigBC::Periodic;
178 using SolverBCShearingPeriodic =
typename SolverConfigBC::ShearingPeriodic;
183 storage.ghost_handler.set(
187 storage.patch_rank_owner,
188 storage.xyzh_ghost_layout});
191 = std::get_if<SolverBCPeriodic>(&solver_config.boundary_config.config)) {
192 storage.ghost_handler.set(
196 storage.patch_rank_owner,
197 storage.xyzh_ghost_layout});
199 SolverBCShearingPeriodic *c
200 = std::get_if<SolverBCShearingPeriodic>(&solver_config.boundary_config.config)) {
201 storage.ghost_handler.set(
205 c->shear_base, c->shear_dir, c->shear_speed * time_val, c->shear_speed},
206 storage.patch_rank_owner,
207 storage.xyzh_ghost_layout});
210 inline void reset_ghost_handler() { storage.ghost_handler.reset(); }
221 using RTree =
typename Config::RTree;
275 Solver(ShamrockCtx &context) : context(context) {}
281 void vtk_do_dump(std::string filename,
bool add_patch_world_id);
283 void set_debug_dump(
bool _do_debug_dump, std::string _debug_dump_filename) {
284 solver_config.set_debug_dump(_do_debug_dump, _debug_dump_filename);
287 inline void print_timestep_logs() {
289 logger::info_ln(
"SPH",
"iteration since start :", solve_logs.get_iteration_count());
290 logger::info_ln(
"SPH",
"time since start :", shambase::details::get_wtime(),
"(s)");
300 set_next_dt(dt_input);
306 Tscal target_time,
i32 niter_max,
f64 max_walltime = -1) {
308 const bool niter_limit_active = (niter_max >= 0);
309 const bool walltime_limit_active = (max_walltime >= 0);
315 "evolve_until (target_time = {:.2f}s, niter_max = {}, max_walltime = "
322 auto synced_wtime = [&]() ->
f64 {
323 if (walltime_limit_active) {
330 Tscal dt = get_dt_sph();
331 Tscal t = get_time();
333 if (t > target_time) {
335 "the target time is higher than the current time");
338 if (t + dt > target_time) {
339 set_next_dt(target_time - t);
344 f64 start_wall_time = (walltime_limit_active) ? synced_wtime() : 0;
346 i32 next_walltime_check_iter
347 = walltime_limit_active ? 1 : std::numeric_limits<i32>::max();
351 while (get_time() < target_time) {
356 if (niter_limit_active && iter_count >= niter_max) {
359 "SPH",
"stopping evolve until because of niter =", iter_count);
362 .reach_target_time =
false,
363 .reach_niter_max =
true,
364 .reach_max_walltime =
false,
365 .iter_count = iter_count,
370 if (walltime_limit_active && iter_count >= next_walltime_check_iter) {
371 f64 global_walltime = synced_wtime();
374 if (global_walltime >= max_walltime) {
379 "stopping evolve until because of "
380 "max_walltime = {:.2f}s > {:.2f}s",
385 .reach_target_time =
false,
386 .reach_niter_max =
false,
387 .reach_max_walltime =
true,
388 .iter_count = iter_count,
393 = (global_walltime - start_wall_time) /
static_cast<f64>(iter_count);
395 auto get_remaining_iters = [&](
f64 delta_walltime,
f64 factor) ->
i32 {
396 if (sec_per_iter > 0) {
397 f64 tmp = factor * delta_walltime / sec_per_iter;
398 if (tmp > std::numeric_limits<i32>::max()) {
399 return std::numeric_limits<i32>::max();
401 return static_cast<i32>(tmp);
406 i32 iters_to_limit = get_remaining_iters(max_walltime - global_walltime, 0.25);
407 i32 iters_to_next_check = iters_to_limit;
409 next_walltime_check_iter = iter_count + std::max(1, iters_to_next_check);
415 "next walltime check in {:.2f}s (niter = {}) global walltime = "
416 "{:.2f}s (max_walltime = {:.2f}s)",
417 iters_to_next_check * sec_per_iter,
425 print_timestep_logs();
428 .reach_target_time =
true,
429 .reach_niter_max =
false,
430 .reach_max_walltime =
false,
431 .iter_count = iter_count,