include/pops/runtime/system/system_stepper.hpp Source File

adc_cpp: include/pops/runtime/system/system_stepper.hpp Source File
adc_cpp 0.3.0
Model-free C++23 core for coupled hyperbolic-elliptic systems on adaptive (AMR) meshes, with MPI and GPU (Kokkos) backends
system_stepper.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <pops/core/state/state.hpp> // kAuxBaseComps (B_z channel read by the condensed source stage)
4#include <pops/core/foundation/types.hpp> // Real
5#include <pops/coupling/source/coupled_source_program.hpp> // CoupledFreqKernel (per-cell coupled frequency)
6#include <pops/mesh/execution/for_each.hpp> // reduce_max_cell (max mu over the cells, device-clean functor)
7#include <pops/parallel/comm.hpp> // all_reduce_min/max (global bounds: identical dt on all ranks)
8#include <pops/runtime/context/grid_context.hpp> // GeometryMode (disk transport dispatch)
9
10#include <stdexcept> // std::runtime_error (disk mode requested without disk advance on a block)
11
12#include <algorithm> // std::min, std::max (CFL: min grid physical step, min dt over the blocks)
13#include <cmath> // std::isfinite, std::ceil (step_cfl / step_adaptive)
14#include <limits> // std::numeric_limits (per-block CFL: dt = min over the blocks)
15#include <string> // last_dt_bound (name of the active bound of the last step_cfl)
16#include <vector>
17
50
51namespace pops {
52namespace stepper {
53
62enum class SplitScheme { Lie, Strang };
63
67template <class Impl>
69 public:
71 explicit SystemStepper(Impl* owner) : owner_(owner) {}
72
74 void set_scheme(SplitScheme scheme) { scheme_ = scheme; }
75 SplitScheme scheme() const { return scheme_; }
76
86 static bool stride_due(int macro_step, int stride) { return (macro_step + 1) % stride == 0; }
87
93 if (owner_->couplings.empty())
94 return;
95 for (auto& c : owner_->couplings)
96 c(dt);
97 }
98
112 void apply_coupled_freq_expr_bounds(double cfl, double& dt, std::string* reason) const {
113 Impl* P = owner_;
114 for (const auto& ce : P->coupled_freq_exprs_) {
115 Real m = 0;
116 if (ce.n_in > 0) {
117 auto& Uref = P->sp[static_cast<std::size_t>(ce.ins[0].sidx)].U;
118 for (int li = 0; li < Uref.local_size(); ++li) {
120 kern.n_in = ce.n_in;
121 kern.n_const = static_cast<int>(ce.kconsts.size());
122 for (int c = 0; c < ce.n_in; ++c) {
123 kern.in[c] = P->sp[static_cast<std::size_t>(ce.ins[static_cast<std::size_t>(c)].sidx)]
124 .U.fab(li)
125 .array();
126 kern.in_comp[c] = ce.ins[static_cast<std::size_t>(c)].comp;
127 }
128 for (int c = 0; c < kern.n_const; ++c)
129 kern.consts[c] = ce.kconsts[static_cast<std::size_t>(c)];
130 kern.prog = ce.prog;
131 m = std::max(m, reduce_max_cell(Uref.box(li), kern));
132 }
133 } else {
134 // Program WITHOUT an input field (constant frequency expressed in bytecode): evaluated once
135 // on the constants alone (no box to traverse); identical on all ranks.
136 Real reg[kCsMaxReg];
137 const int nc = static_cast<int>(ce.kconsts.size());
138 for (int c = 0; c < nc; ++c)
139 reg[c] = ce.kconsts[static_cast<std::size_t>(c)];
140 const Real mu0 = ce.prog.eval(reg);
141 if (mu0 > Real(0))
142 m = mu0;
143 }
144 const double mu = all_reduce_max(static_cast<double>(m)); // ALL ranks (collective symmetry)
145 if (mu > 0.0) {
146 const double dt_cs = cfl / mu;
147 if (dt_cs < dt) {
148 dt = dt_cs;
149 if (reason)
150 *reason = "coupled_source:" + ce.label;
151 }
152 }
153 }
154 }
155
160 Real cfl_grid_h() const {
161 Impl* P = owner_;
162 return P->polar_ ? std::min(P->pgeom_.dr(), P->pgeom_.r_min * P->pgeom_.dtheta())
163 : std::min(P->geom.dx(), P->geom.dy());
164 }
165
175 void apply_global_dt_bounds(double& dt, std::string* reason) const {
176 Impl* P = owner_;
177 for (const auto& g : P->dt_bounds_) {
178 if (!g.fn)
179 continue;
180 double v = g.fn();
181 if (!(v > 0.0) || !std::isfinite(v))
182 v = std::numeric_limits<double>::infinity();
183 v = all_reduce_min(v);
184 if (v < dt) {
185 dt = v;
186 if (reason)
187 *reason = "global:" + g.label;
188 }
189 }
190 }
191
203 for (auto& s : owner_->sp) {
204 if (!s.evolve)
205 continue; // bloc gele : fond fixe jamais modifie, rien a projeter
206 if (s.project)
207 s.project(s.U);
208 }
209 }
210
221 void run_source_stage(typename Impl::Species& s, Real eff_dt) {
222 // GEOMETRY DISPATCH (Path A step 2c): a block carries AT MOST ONE condensed source stage (set_source_stage
223 // builds the Cartesian OR the polar one depending on the System geometry). The POLAR one
224 // (PolarCondensedSchurSourceStepper, #212) has the SAME step(state, phi, bz, c_bz, theta, dt) signature as
225 // the Cartesian one (#126): only the pointer changes. The Cartesian path stays BIT-IDENTICAL (schur_polar
226 // == nullptr in Cartesian -> we take the original schur branch, unchanged).
227 if (s.schur_polar) {
228 s.schur_polar->step(s.U, owner_->fields_.ell_phi(), owner_->aux, s.schur_bz_comp,
229 static_cast<Real>(s.schur_theta), eff_dt);
230 return;
231 }
232 if (s.schur) {
233 s.schur->step(s.U, owner_->fields_.ell_phi(), owner_->aux, s.schur_bz_comp,
234 static_cast<Real>(s.schur_theta), eff_dt);
235 return;
236 }
237 // GENERIC SOURCE STAGE (fallback): plays ONLY if NO condensed Schur stage (production path
238 // UNTOUCHED, bit-identical). Advances the block source stage IN PLACE on eff_dt. nullptr
239 // (default) -> no-op, as before. Used by generic splitting (pops.Strang) and order tests.
240 if (s.source_step)
241 s.source_step(s.U, eff_dt);
242 }
243
257 void advance_transport_n(typename Impl::Species& s, Real dt, int n) {
258 const GeometryMode mode = owner_->geometry_mode_;
259 if (mode == GeometryMode::None || !owner_->eb_set_) {
260 s.advance(s.U, dt,
261 n); // default path (or mode without a fixed embedded boundary): BIT-IDENTICAL
262 return;
263 }
264 if (mode == GeometryMode::Staircase) {
265 if (!s.advance_masked)
266 throw std::runtime_error(
267 "SystemStepper: embedded-boundary mode 'staircase' requested but block '" + s.name +
268 "' exposes no masked transport advance (level-set transport not wired for this block)");
269 s.advance_masked(s.U, dt, n);
270 return;
271 }
272 // CutCell
273 if (!s.advance_eb)
274 throw std::runtime_error(
275 "SystemStepper: embedded-boundary mode 'cutcell' requested but block '" + s.name +
276 "' exposes no cut-cell EB transport advance (level-set transport not wired for this "
277 "block)");
278 s.advance_eb(s.U, dt, n);
279 }
280
283 void advance_transport(typename Impl::Species& s, Real eff_dt) {
284 advance_transport_n(s, eff_dt, s.substeps);
285 }
286
289 void advance_transport_half(typename Impl::Species& s, Real eff_dt) {
290 advance_transport_n(s, Real(0.5) * eff_dt, s.substeps);
291 }
292
303 void advance_due_blocks(double dt) {
304 Impl* P = owner_;
305 for (auto& s : P->sp) {
306 if (!s.evolve)
307 continue; // frozen block: not advanced
308 if (!stride_due(P->macro_step_, s.stride))
309 continue; // hold: not at the stride window end
310 const Real eff_dt = Real(dt) * Real(s.stride); // catch-up: effective step s.stride * dt
312 eff_dt); // transport DISPATCHED by the geometry mode (None: assemble_rhs)
313 run_source_stage(s, eff_dt); // OPT-IN: Schur-condensed source stage (no-op otherwise)
314 }
315 }
316
337 void run_program_cadence(double dt) {
338 Impl* P = owner_;
339 if (stride_due(P->macro_step_, P->program_stride_)) {
340 const Real eff_dt = Real(dt) * Real(P->program_stride_); // catch-up: effective step M*dt
341 const int n = P->program_substeps_;
342 const Real h = eff_dt / Real(n); // substeps subdivide the EFFECTIVE step (native: eff_dt/n)
343 for (int sub = 0; sub < n; ++sub)
344 P->program_step_(h);
345 }
346 P->t += dt; // clock ticks EVERY macro-step (held steps included), like native
347 P->macro_step_++;
348 }
349
355 void step(double dt) {
356 if (scheme_ == SplitScheme::Strang) {
357 step_strang(dt);
358 return;
359 }
360 Impl* P = owner_;
361 // Compiled time Program (epic ADC-399): when a problem.so has installed a macro-step body, IT owns
362 // the whole step (solve_fields, RHS, combine, commit -- all via ProgramContext). The runtime only
363 // keeps the clock coherent (the SYSTEM-level substeps + stride cadence + clock tick are factored
364 // into run_program_cadence, shared with step_cfl so both route a program the same way -- ADC-413).
365 // No implicit solve_fields / couplings / projections here: the Program expresses them explicitly.
366 if (P->program_step_) {
368 return;
369 }
370 // COUPLING / POISSON: solve_fields assembles f = Sum_s elliptic_rhs_s(U_s) on the CURRENT state of
371 // each block. A HELD block (cadence M, outside the window end) contributes with its STALE state (its
372 // last advance, thus frozen until its next catch-up): stale density / charge in the Poisson sum as
373 // long as it has not caught up. Assumed stride choice (loose coupling of the slow block).
374 P->solve_fields();
376 dt); // DUE blocks: catch-up transport + opt-in source stage (shared with step_cfl)
377 apply_couplings(Real(dt)); // inter-species coupled sources (splitting), after transport
378 apply_projections(); // projection ponctuelle POST-PAS ENTIER (ADC-177) ; no-op sans projection
379 P->t += dt;
380 P->macro_step_++;
381 }
382
406 void step_strang(double dt) {
407 Impl* P = owner_;
408 // (1) phi consistent with rho^n, for the 1st transport half-advance.
409 P->solve_fields();
410 // (2) H(dt/2): 1st transport half-advance of each DUE block. s.substeps substeps (unchanged).
411 // Dispatched by the geometry mode (None: assemble_rhs; Staircase/CutCell: disk operator).
412 for (auto& s : P->sp) {
413 if (!s.evolve)
414 continue;
415 if (!stride_due(P->macro_step_, s.stride))
416 continue;
417 const Real eff_dt = Real(dt) * Real(s.stride);
418 advance_transport_half(s, eff_dt);
419 }
420 // (3) phi RE-SOLVED on the post-H(dt/2) density, for the source stage.
421 P->solve_fields();
422 // (4) S(dt): FULL source stage of each DUE block (no-op if no Schur stage, like Lie).
423 for (auto& s : P->sp) {
424 if (!s.evolve)
425 continue;
426 if (!stride_due(P->macro_step_, s.stride))
427 continue;
428 const Real eff_dt = Real(dt) * Real(s.stride);
429 run_source_stage(s, eff_dt);
430 }
431 // (5) phi RE-SOLVED on the post-source density: WITHOUT this solve the 2nd half-advance would read a
432 // stale phi (cf. docs/HOFFART_STEP_SEQUENCE.md, the single head solve_fields is insufficient).
433 P->solve_fields();
434 // (6) H(dt/2): 2nd transport half-advance, closing the symmetric Strang step. SAME dispatch.
435 for (auto& s : P->sp) {
436 if (!s.evolve)
437 continue;
438 if (!stride_due(P->macro_step_, s.stride))
439 continue;
440 const Real eff_dt = Real(dt) * Real(s.stride);
441 advance_transport_half(s, eff_dt);
442 }
444 Real(dt)); // inter-species coupled sources (splitting), after the symmetric step
445 // Projection ponctuelle POST-PAS ENTIER (ADC-177) : UNE application apres le pas Strang complet
446 // H(dt/2) S(dt) H(dt/2), jamais entre les etages (semantique post-pas, pas post-etage).
448 P->t += dt;
449 P->macro_step_++;
450 }
451
453 void advance(double dt, int nsteps) {
454 for (int s = 0; s < nsteps; ++s)
455 step(dt);
456 }
457
482 double step_cfl(double cfl) {
483 Impl* P = owner_;
484 P->solve_fields();
485 // MIN physical step of the grid (Cartesian min(dx,dy) / polar min(dr, r_min*dtheta), cf.
486 // cfl_grid_h). The rest of the CFL formula (per block, substeps/stride) is unchanged.
487 const Real h = cfl_grid_h();
488 // PER-BLOCK CFL, STRIDE AND SUBSTEPS FACTOR INCLUDED. A block of cadence M advances by an effective
489 // step M*dt in substeps_b substeps, so each substep is worth stride_b * dt / substeps_b: the stable
490 // condition per substep is stride_b * dt / substeps_b <= cfl * h / w_b, that is
491 // dt <= cfl * h * substeps_b / (stride_b * w_b).
492 // The GLOBAL dt is the min over the evolving blocks (the most constraining). Without this, the step
493 // computed on w_max alone then multiplied by M would violate the CFL by a factor M on the stride block.
494 //
495 // BACKWARD COMPATIBILITY (post-#121). The formula is SUBSTEPS-AWARE: with substeps_b > 1, the dt
496 // returned is substeps_b times larger than the old formula dt = cfl*h/(stride*w).
497 // bit-identical only for substeps=1 (at any stride); step_cfl is now substeps-aware
498 // (dt = cfl*h*substeps/(stride*w)), so a step_cfl run with substeps>1 advances a larger dt
499 // than before #121 (CFL-maximal step, each substep at the stability limit).
500 // To reproduce a run calibrated with the old formula, use step(dt) with the explicit historical
501 // dt, NOT step_cfl.
502 double dt = std::numeric_limits<double>::infinity();
503 std::string reason = "degenerate";
504 for (auto& s : P->sp) {
505 if (!s.evolve)
506 continue; // frozen block: does not constrain the step
507 const Real w = std::max(s.max_speed(s.U), kCflSpeedFloor);
508 double dt_b = cfl * static_cast<double>(h) * static_cast<double>(s.substeps) /
509 (static_cast<double>(s.stride) * static_cast<double>(w));
510 const char* why = "transport";
511 // SOURCE FREQUENCY bound (optional; mu <= 0 = does not constrain).
512 if (s.source_frequency) {
513 const Real mu = s.source_frequency(s.U);
514 if (mu > Real(0)) {
515 const double dt_src = cfl * static_cast<double>(s.substeps) /
516 (static_cast<double>(s.stride) * static_cast<double>(mu));
517 if (dt_src < dt_b) {
518 dt_b = dt_src;
519 why = "source_frequency";
520 }
521 }
522 }
523 // Direct ADMISSIBLE STEP (optional; <= 0 = does not constrain; cfl NOT applied).
524 if (s.stability_dt) {
525 const Real db = s.stability_dt(s.U);
526 if (db > Real(0)) {
527 const double dt_adm = static_cast<double>(db) * static_cast<double>(s.substeps) /
528 static_cast<double>(s.stride);
529 if (dt_adm < dt_b) {
530 dt_b = dt_adm;
531 why = "stability_dt";
532 }
533 }
534 }
535 if (dt_b < dt) {
536 dt = dt_b;
537 reason = std::string(why) + ":" + s.name;
538 }
539 }
540 // DECLARED frequencies of the coupled sources (CoupledSource.frequency): the couplings
541 // apply ONCE per MACRO-step (apply_couplings(dt)), so the bound applies to the
542 // macro-dt directly: dt <= cfl / mu (NO substeps/stride factor -- those apply
543 // only to the block subcycled transport, not to the coupling splitting).
544 for (const auto& cs : P->coupled_freqs_) {
545 if (!(cs.mu > 0.0))
546 continue;
547 const double dt_cs = cfl / cs.mu;
548 if (dt_cs < dt) {
549 dt = dt_cs;
550 reason = "coupled_source:" + cs.label;
551 }
552 }
553 // PER-CELL frequencies (CoupledSource.frequency with an Expr): mu(U) reduced (MAX) per cell at
554 // this step, global all_reduce_max, dt <= cfl / max(mu). Same reason "coupled_source:<label>" as the
555 // constant. No per-cell source -> no-op (bit-identical).
556 apply_coupled_freq_expr_bounds(cfl, dt, &reason);
557 // GLOBAL bounds (System::add_dt_bound): all_reduce_min over the registered bounds, tracking the
558 // winning reason (see apply_global_dt_bounds for the MPI deadlock-safety rationale).
559 apply_global_dt_bounds(dt, &reason);
560 // OPTIONAL compiled-Program dt bound (epic ADC-399 / ADC-417, spec s18). When the installed Program
561 // exported one (System::install_program stored program_dt_bound_), it TIGHTENS dt to the min of the
562 // native CFL dt above and the program's own bound. No program / no bound -> the closure is empty and
563 // dt is the native CFL UNCHANGED. The native CFL logic above is left intact: this only reduces dt.
564 // MPI-SAFE: program_dt_bound_ runs the SAME collective reduction (block_max_speed / reductions) on
565 // every rank, so the bound is rank-uniform -- like apply_global_dt_bounds, the min keeps the step
566 // collectives symmetric (no desync / deadlock).
567 if (P->program_dt_bound_) {
568 const double pb = static_cast<double>(P->program_dt_bound_(static_cast<Real>(cfl)));
569 if (std::isfinite(pb) && pb > 0.0 && pb < dt) {
570 dt = pb;
571 reason = "program:dt_bound";
572 }
573 }
574 if (!std::isfinite(dt)) {
575 dt = cfl * static_cast<double>(h) /
576 static_cast<double>(kCflSpeedFloor); // all frozen: degenerate step
577 reason = "degenerate";
578 }
579 last_dt_reason_ = std::move(reason);
580 // Compiled time Program (epic ADC-399, criterion 7): the CFL dt above is computed in adc_cpp ON
581 // THE NATIVE STATE (per-block bounds + global bounds, UNCHANGED -- the CFL logic stays here), then
582 // the installed Program drives the macro-step at that dt via the SHARED cadence helper. step_cfl
583 // thus conserves the existing CFL logic AND calls the Program. Semantics match step()'s program
584 // branch EXACTLY: run the cadence + tick the clock, with NO apply_couplings / apply_projections
585 // (the Program expresses solve_fields / couplings / projections itself). The native advance path
586 // below is taken ONLY when no program is installed. (step_adaptive -- multirate -- still drives
587 // only the native path; a Program is whole-system, so multirate subcycling does not apply.)
588 if (P->program_step_) {
590 return dt;
591 }
593 dt); // DUE blocks: catch-up transport + opt-in source stage (shared with step Lie)
595 apply_projections(); // projection ponctuelle POST-PAS ENTIER (ADC-177) ; no-op sans projection
596 P->t += dt;
597 P->macro_step_++;
598 return dt;
599 }
600
609 double step_adaptive(double cfl) {
610 Impl* P = owner_;
611 P->solve_fields();
612 // Multirate: macro-step = stable step of the SLOWEST block; each faster block is
613 // subcycled n_b. aux frozen over the macro-step (coupling once-per-step). STRIDE SEMANTICS =
614 // hold-then-catch-up: a block of cadence M is HELD as long as (macro_step + 1) % M != 0, then
615 // advances by an effective step M*macro_dt at the window end (cf. stride_due).
616 Real wmin = Real(1e30);
617 std::vector<Real> wb;
618 wb.reserve(P->sp.size());
619 for (auto& s : P->sp) {
620 const Real w = s.evolve ? s.max_speed(s.U) : Real(0); // frozen block: out of cadence
621 wb.push_back(w);
622 if (s.evolve)
623 wmin = std::min(wmin, w);
624 }
625 if (wmin >= Real(1e30))
626 wmin = kCflSpeedFloor; // no evolving block (all frozen)
627 const Real h = cfl_grid_h(); // Cartesian min(dx,dy) / polar min(dr, r_min*dtheta)
628 double macro_dt = cfl * static_cast<double>(h) / static_cast<double>(wmin);
629 // OPTIONAL block bounds: each block subcycles n_b times its effective step
630 // stride_b*macro_dt; the substep stride_b*macro_dt/n_b must satisfy the source / admissible
631 // step bounds of the block. n_b (formula identical to the advance loop below) does not depend
632 // on macro_dt: the clamp is done BEFORE the advance, n_b stays consistent.
633 for (std::size_t b = 0; b < P->sp.size(); ++b) {
634 auto& s = P->sp[b];
635 if (!s.evolve)
636 continue;
637 if (!s.source_frequency && !s.stability_dt)
638 continue;
639 int n = static_cast<int>(
640 std::ceil(static_cast<double>(s.stride) * static_cast<double>(wb[b] / wmin)));
641 if (n < 1)
642 n = 1;
643 if (s.source_frequency) {
644 const Real mu = s.source_frequency(s.U);
645 if (mu > Real(0))
646 macro_dt =
647 std::min(macro_dt, cfl * static_cast<double>(n) /
648 (static_cast<double>(s.stride) * static_cast<double>(mu)));
649 }
650 if (s.stability_dt) {
651 const Real db = s.stability_dt(s.U);
652 if (db > Real(0))
653 macro_dt = std::min(macro_dt, static_cast<double>(db) * static_cast<double>(n) /
654 static_cast<double>(s.stride));
655 }
656 }
657 // Declared frequencies of the coupled sources (cf. step_cfl): bound on the MACRO-step.
658 for (const auto& cs : P->coupled_freqs_) {
659 if (cs.mu > 0.0)
660 macro_dt = std::min(macro_dt, cfl / cs.mu);
661 }
662 // PER-CELL frequencies (Expr): MAX of mu(U) per cell, all_reduce_max, bound on the macro-step
663 // (cf. step_cfl). step_adaptive does not track the active reason -> reason = nullptr.
664 apply_coupled_freq_expr_bounds(cfl, macro_dt, nullptr);
665 // GLOBAL bounds (System::add_dt_bound), like step_cfl; step_adaptive does not track the active
666 // reason -> nullptr (same all_reduce_min, identical dt on all ranks).
667 apply_global_dt_bounds(macro_dt, nullptr);
668 for (std::size_t b = 0; b < P->sp.size(); ++b) {
669 auto& s = P->sp[b];
670 if (!s.evolve)
671 continue; // frozen block: not advanced
672 if (!stride_due(P->macro_step_, s.stride))
673 continue; // hold: not at the stride window end
674 // Stable subcycling of the EFFECTIVE step M*macro_dt: each substep must satisfy
675 // M*macro_dt / n <= cfl*h / w_b, i.e. n >= ceil(M * w_b / w_min). The stride factor M is thus
676 // carried by the number of substeps (without it, n on w_b/w_min alone would violate the CFL by a factor M).
677 int n = static_cast<int>(
678 std::ceil(static_cast<double>(s.stride) * static_cast<double>(wb[b] / wmin)));
679 if (n < 1)
680 n = 1;
681 const Real eff_dt = Real(macro_dt) * Real(s.stride); // catch-up: effective step M*macro_dt
682 advance_transport_n(s, eff_dt,
683 n); // transport DISPATCHED by the geometry mode (n adaptive substeps)
684 run_source_stage(s, eff_dt); // OPT-IN: Schur-condensed source stage (no-op otherwise)
685 }
686 apply_couplings(Real(macro_dt));
687 apply_projections(); // projection ponctuelle POST-MACRO-PAS (ADC-177), pas par sous-cycle
688 P->t += macro_dt;
689 P->macro_step_++;
690 return macro_dt;
691 }
692
696 const std::string& last_dt_reason() const { return last_dt_reason_; }
697
698 private:
699 Impl* owner_;
700 SplitScheme scheme_ = SplitScheme::Lie; // default Lie (Godunov): bit-identical to history
701 std::string last_dt_reason_; // active bound of the last step_cfl (diagnostic)
702};
703
704} // namespace stepper
705} // namespace pops
SystemStepper<Impl>: see the contract above.
Definition system_stepper.hpp:68
Real cfl_grid_h() const
MIN physical step of the grid, shared by step_cfl / step_adaptive: Cartesian = min(dx,...
Definition system_stepper.hpp:160
SystemStepper(Impl *owner)
Definition system_stepper.hpp:71
void run_program_cadence(double dt)
Runs ONE macro-step of length dt through an INSTALLED compiled time Program (epic ADC-399): the SYSTE...
Definition system_stepper.hpp:337
void apply_projections()
PROJECTION PONCTUELLE post-pas (ADC-177) : U <- project(U, aux) par bloc, appliquee UNE fois a la FIN...
Definition system_stepper.hpp:202
void advance_transport(typename Impl::Species &s, Real eff_dt)
TRANSPORT ADVANCE of block s over eff_dt in s.substeps substeps, dispatched by the mode (cf.
Definition system_stepper.hpp:283
void apply_couplings(Real dt)
Inter-species COUPLING sources: applied by SPLITTING (one explicit additive step of dt) AFTER the tra...
Definition system_stepper.hpp:92
static bool stride_due(int macro_step, int stride)
True if a block of cadence stride CATCHES UP at this macro-step (END of window).
Definition system_stepper.hpp:86
double step_cfl(double cfl)
One macro-step at CFL dt: dt = min over the evolving blocks of the block step BOUNDS,...
Definition system_stepper.hpp:482
double step_adaptive(double cfl)
One MULTIRATE macro-step: the macro-step = stable step of the SLOWEST block; each faster block is sub...
Definition system_stepper.hpp:609
void advance_transport_n(typename Impl::Species &s, Real dt, int n)
TRANSPORT ADVANCE of block s over dt in n substeps, DISPATCHED by the System geometry mode (worksite ...
Definition system_stepper.hpp:257
SplitScheme scheme() const
Definition system_stepper.hpp:75
void advance_transport_half(typename Impl::Species &s, Real eff_dt)
HALF transport advance (Strang): dispatch of advance_transport over half_dt = eff_dt/2 – the disk mod...
Definition system_stepper.hpp:289
void apply_global_dt_bounds(double &dt, std::string *reason) const
GLOBAL step bounds (System::add_dt_bound): multi-block coupling, Schur/Poisson, AMR/scheduler.
Definition system_stepper.hpp:175
void apply_coupled_freq_expr_bounds(double cfl, double &dt, std::string *reason) const
Step bound from PER-CELL COUPLED FREQUENCIES (CoupledSource.frequency with an Expr,...
Definition system_stepper.hpp:112
void run_source_stage(typename Impl::Species &s, Real eff_dt)
Schur-CONDENSED SOURCE STAGE (OPT-IN, cf.
Definition system_stepper.hpp:221
void advance(double dt, int nsteps)
Advances by nsteps macro-steps of length dt (loop over step).
Definition system_stepper.hpp:453
void step(double dt)
One macro-step of length dt.
Definition system_stepper.hpp:355
void set_scheme(SplitScheme scheme)
Chooses the time splitting policy (default Lie = bit-identical). See SplitScheme.
Definition system_stepper.hpp:74
void step_strang(double dt)
One STRANG macro-step (symmetric, 2nd order): H(dt/2); S(dt); H(dt/2).
Definition system_stepper.hpp:406
void advance_due_blocks(double dt)
FULL-STEP advance of every DUE block over dt: effective step eff_dt = stride * dt (cadence catch-up),...
Definition system_stepper.hpp:303
const std::string & last_dt_reason() const
Name of the ACTIVE bound (the one that fixed dt) of the last step_cfl: "transport:<block>",...
Definition system_stepper.hpp:696
Parallel seam: minimal MPI abstraction (rank/size + collectives) with serial fallback.
Generic COUPLED SOURCE interpreter: postfix bytecode evaluated on device (P5 phase 1).
for_each_cell and reductions: the parallelism SEAM over the cells of a Box2D; sync_host / sync_device...
Block grid context plus closures, shared between System (which installs them) and block_builder....
SplitScheme
Time SPLITTING policy of the macro-step (hyperbolic transport H + source stage S).
Definition system_stepper.hpp:62
Definition amr_hierarchy.hpp:29
constexpr Real kCflSpeedFloor
Speed FLOOR for the CFL step policies (audit 2026-06, explicit constant instead of the scattered lite...
Definition types.hpp:38
double Real
Definition types.hpp:30
constexpr int kCsMaxReg
Definition coupled_source_program.hpp:40
Real reduce_max_cell(const Box2D &b, F f)
MAX reduction with a REDUCING FUNCTOR: f receives (i, j, Real& acc) and updates acc,...
Definition for_each.hpp:240
double all_reduce_max(double x)
Definition comm.hpp:146
double all_reduce_min(double x)
Definition comm.hpp:149
GeometryMode
TRANSPORT GEOMETRY MODE of the macro-step (T5-PR3 effort, disc wiring in System::step).
Definition grid_context.hpp:29
Pointwise types of the physics layer: StateVec<N> (conserved state) and Aux (auxiliary fields from th...
Definition coupled_source_program.hpp:175
CsProgram prog
Definition coupled_source_program.hpp:183
Real consts[kCsMaxReg]
Definition coupled_source_program.hpp:180
int in_comp[kCsMaxReg]
Definition coupled_source_program.hpp:177
int n_const
Definition coupled_source_program.hpp:181
int n_in
Definition coupled_source_program.hpp:178
Array4 in[kCsMaxReg]
Definition coupled_source_program.hpp:176
Base scalar types and the POPS_HD macro (host+device portability).