Global Ocean Dynamic Adjustment
date: 2026/03/22
Contributors: Xylar Asay-Davis, Codex, Claude
Summary
This design document describes a new Polaris capability for dynamic adjustment
of global-ocean initial conditions. The intent is to port the core idea from
Compass’ compass/ocean/tests/global_ocean/dynamic_adjustment workflow: a
sequence of short MPAS-Ocean forward runs with stage-specific time steps,
damping, and restart/output intervals that dissipate fast waves generated by
the initial condition before a longer production simulation begins.
The new Polaris capability should support the same qualitative workflow for
MPAS-Ocean or Omega, selected by the [ocean] model config option. A developer
should be able to describe a staged adjustment schedule over several days to
roughly a month, with progressively less damping and typically increasing time
steps, and Polaris should turn that schedule into an inspectable sequence of
model steps. Each stage should produce restart files and optional diagnostics so
the developer can verify that the solution is settling down and can continue
from the final relaxed state.
The primary software challenge is not the numerical method itself but the workflow abstraction: Polaris needs a reusable way to describe and execute a chain of forward model stages while mapping common stage settings onto model-specific MPAS-Ocean and Omega configuration options. This design is successful if Polaris can express the existing Compass-style schedules in a compact configuration file, execute them as a restart chain for the configured model, and leave a clean path for model-specific tuning and validation as the capability matures.
The capability has landed for MPAS-Ocean and Omega, with schedules for all five unified meshes, and both models have run it end to end on all five; Omega’s damped stages need an Omega build with Rayleigh damping. The parts of this document that the implementation changed are the validation strategy — there is deliberately no automated settling criterion — and the schedule format, which became a delta on the forward-run config options rather than a self-contained description of a run. Both are recorded in the sections below.
Requirements
Requirement: A staged dynamic-adjustment workflow can be created from a global initial condition
Date last modified: 2026/03/22
Contributors: Xylar Asay-Davis, Codex
Polaris shall provide a workflow that begins from a global-ocean initial condition and runs a sequence of forward-model stages intended to dissipate fast external and internal waves introduced by initialization.
The workflow shall support schedules spanning from a few days to roughly a month, depending on mesh resolution and model stability needs.
Each stage shall support its own run duration and restart/output cadence and shall allow stage-specific control over time stepping and damping.
Requirement: The same conceptual workflow supports either MPAS-Ocean or Omega
Date last modified: 2026/06/14
Contributors: Xylar Asay-Davis, Codex, Claude
Polaris shall support dynamic adjustment for either MPAS-Ocean or Omega through
a common workflow description rather than two unrelated task designs. The target
model is selected by the [ocean] model config option; a given task targets
exactly one model and consumes that model’s initial condition.
The common description shall allow Polaris to represent concepts such as stage duration, time-step selection, damping strength, and restart chaining even if the exact model configuration options differ between MPAS-Ocean and Omega.
Requirement: Dynamic adjustment is decomposed into inspectable restart stages
Date last modified: 2026/03/22
Contributors: Xylar Asay-Davis, Codex
The workflow shall be organized into individual Polaris steps or substeps, one per stage of the dynamic-adjustment schedule.
Each stage shall consume either the original initial condition or the restart from the preceding stage and shall produce a restart suitable for the next stage. The final stage shall produce a relaxed restart that can be used for subsequent simulation workflows.
Requirement: Adjustment schedules are reusable but easy to tune
Date last modified: 2026/03/22
Contributors: Xylar Asay-Davis, Codex
Polaris shall support reusable default schedules for common global meshes while also allowing users or developers to modify durations, damping values, and time steps without changing Python source code.
The design shall make it straightforward to port existing Compass schedules into Polaris and later refine them as model behavior or stability limits change.
Requirement: The workflow includes basic validation that the adjustment remained well behaved
Date last modified: 2026/03/22
Contributors: Xylar Asay-Davis, Codex
Polaris shall provide at least basic validation that the dynamic-adjustment sequence completed successfully and did not produce obviously unphysical results.
This validation does not need to prove that the schedule is scientifically optimal, but it should detect clear failures such as numerical blow-up, missing restart chaining, or gross excursions in key diagnostics.
Algorithm Design
Algorithm Design: A staged dynamic-adjustment workflow can be created from a global initial condition
Date last modified: 2026/08/11
Contributors: Xylar Asay-Davis, Codex, Claude
The workflow is described by an ordered schedule in YAML, containing a small number of shared options plus a list of stages. Each stage may contain:
A stage name (the mapping key).
A run duration.
An output interval.
A restart interval.
Time-step information, either explicit (
dt/btr_dt) or derived from mesh resolution (dt_per_km/btr_dt_per_km).Damping settings, typically decreasing from one stage to the next.
Every schedule key maps directly onto a field of the reusable, model-agnostic
ForwardStage object introduced by the realistic_global forward workflow, so
the schedule parser is a thin adapter rather than a second configuration
system. The keys use Polaris-native names (stages, damping) rather than the
Compass names, but the mental model is the same: a sequence of several
damped_adjustment_* stages followed by a final simulation stage, which has
proven useful across several global meshes.
The relationship between the schedule and the config options turned out to be
the important design decision, and it went further than “maps onto
ForwardStage”. A stage is a forward run, so it starts from the
[realistic_global_forward] config options for its mesh — including the
per-mesh overrides — and the schedule supplies only what varies from stage to
stage. The horizontal mixing coefficients, the eddy parameterizations and the
time integrators are therefore the same as they would be for a forward run on
that mesh, and no schedule mentions them. Keeping the schedule a delta is what
stops it from becoming a second configuration system that has to track
ForwardStage field by field.
The corollary is that a schedule key must name a real forward-run setting. A key
that names nothing is an error at setup rather than a silent fall back to the
config value, so a schedule cannot quietly go stale when an option is renamed.
Damping runs the other way round from every other option: it is off in config
and turned on per stage, so the final simulation stage gets an undamped run
simply by omitting it.
Algorithm Design: The same conceptual workflow supports either MPAS-Ocean or Omega
Date last modified: 2026/10/26
Contributors: Xylar Asay-Davis, Codex, Claude
The schedule should be model-agnostic. Polaris should interpret the schedule into a common internal representation and then map each stage into model configuration options appropriate for the configured ocean model.
For MPAS-Ocean, this mapping will likely include familiar options such as
config_dt, config_btr_dt, restart flags, and the Rayleigh damping controls
used in Compass. For Omega, Polaris should provide a model-specific translator
that applies the closest available controls for time stepping, restart
behavior, output cadence, and damping.
The initial implementation does not need to guarantee that MPAS-Ocean and Omega use identical low-level damping controls. The requirement is instead that either model can participate in the same staged-adjustment workflow abstraction and that model-specific differences are isolated in one place.
That isolation landed in the forward workflow rather than here: the mapping is
ForwardStage.model_replacements and the mpaso_to_omega.yaml translation the
model-neutral template already goes through, so this workflow contributes no
model-specific code of its own. Damping is the one control that is not a
translation: Omega’s RayleighDamping applies the same drag in every layer, in
the implicit vertical-mixing solve, but MPAS-Ocean turns its damping on through
the bottom-drag type rather than a switch of its own. The forward step adds the
group to a damped stage’s Omega config directly, and leaves it out of an
undamped one, so that only damped stages need an Omega build that has it.
Algorithm Design: Dynamic adjustment is decomposed into inspectable restart stages
Date last modified: 2026/03/22
Contributors: Xylar Asay-Davis, Codex
Polaris should create one model-running step per adjustment stage. The first stage should start from the initial condition produced by the corresponding global-ocean initialization workflow. Each later stage should start from the restart written by the previous stage.
This stepwise structure makes the workflow easy to inspect and debug. If a particular stage is unstable or clearly overdamped, the user can examine that stage’s configuration and outputs without having to reason about a single large monolithic run script.
The workflow should also compute each stage’s start and stop time from the ordered schedule so restart filenames and model start times are deterministic and do not need to be entered redundantly by hand.
Algorithm Design: Adjustment schedules are reusable but easy to tune
Date last modified: 2026/08/11
Contributors: Xylar Asay-Davis, Codex, Claude
The most practical near-term design is to store default schedules in small YAML files associated with a mesh, task, or mesh family, following the same pattern Compass already uses.
Polaris should support two complementary modes:
A default mesh-specific schedule that can be checked into the repository.
User overrides through Polaris config options or an alternate schedule file.
This keeps the common case simple while avoiding hard-coded stage definitions in Python.
Both landed: a checked-in <mesh_name>.yaml when the mesh has one and
default.yaml otherwise, with a schedule config option naming an alternate
file. The one constraint worth stating is that the set of steps depends on the
schedule, and a Polaris step graph is fixed at setup. So a schedule change takes
effect at polaris setup, not at run time, and the task rebuilds its stages
during configure() — after the user’s config has been merged — because a stage
whose name survived a change would otherwise come back from the shared-step
cache still carrying its old run duration.
Algorithm Design: The workflow includes basic validation that the adjustment remained well behaved
Date last modified: 2026/08/11
Contributors: Xylar Asay-Davis, Codex, Claude
Validation focuses on clear failure modes rather than exhaustive physical assessment. The strategy as implemented is:
Confirm that each stage completed and wrote the restart the next stage consumes (enforced by the Polaris dependency graph and each stage’s declared input/output restart files).
Bound the maximum
temperature, the maximumsalinityand the maximum CFL number reached at any point in each stage, to catch numerical blow-up and a time step too long for the flow the stage produced.Collect a per-stage diagnostics table and plot the underlying time series, so that whether the adjustment settled is read by a person rather than asserted by a threshold.
Compare a small set of final-state variables against a baseline for regression testing.
Item 4 of the earlier strategy — requiring the maximum cell kinetic energy to flatten over the last few stages — was removed. It was rewritten three times (kinetic-energy levels, then the fractional change stage over stage, then that change per unit time) and every revision was forced by a healthy run failing it. The quantity is not comparable across stages: a schedule’s stages differ in length by up to 70x, the final stage switches the damping off so its energy rises by design, and a stage whose energy happens to dip makes the next ordinary rise read as an acceleration. Three samples cannot separate any of that from a run that is genuinely running away. Whether an adjustment settled is now read from the diagnostics table and the figure, which show the whole series; the checks that remain are bounds on quantities with real failure modes behind them. An automated settling criterion should not be re-added without evidence that it survives schedules whose stages differ in length and damping.
The other change is where the numbers come from. Rather than reading
output.nc, the checks read each stage’s global-statistics file wherever the
configured model reports the quantity, because the model has already reduced it
over the whole domain at the statistics cadence — so an excursion in the middle
of a stage is visible, which it is not in an end-of-stage field. output.nc is
the fallback, and only for maxima and minima, which mean the same thing however
they are obtained. A volume-weighted mean does not, so a metric the model does
not report is left blank rather than quietly replaced with an unweighted one.
Two exclusions make the bounds mean what they say. A stage is never judged on the sample written before its first time step: for the first stage that sample is the initial condition, which dynamic adjustment did not produce, and for every later stage it is the predecessor’s final state, which that stage’s own check already covered. And the tracer bounds ignore a configurable window at the start of the sequence, over which the initial condition’s artifacts are still mixing away. The window is measured from the sequence rather than from each stage deliberately: what it skips belongs to the initial condition, and a per-stage window would instead stop watching just after every damping change, which is where a schedule that steps the damping down too fast would show itself. For the same reason the CFL bound does not get the window at all.
Implementation
Implementation: A staged dynamic-adjustment workflow can be created from a global initial condition
Date last modified: 2026/09/24
Contributors: Xylar Asay-Davis, Codex, Claude
Polaris adds a realistic_global dynamic-adjustment task that consumes the
outputs of the shared realistic_global/init steps. The task reads a schedule
file and instantiates one forward model step per stage, reusing the
realistic_global Forward step and its ForwardStage settings object
unchanged.
The schedule uses Polaris-native keys that name ForwardStage fields, which is
to say [realistic_global_forward] config options. A shared block supplies
per-stage defaults; each stage overrides what it needs. The u-oi240-lr240
schedule, shortened:
dynamic_adjustment:
shared:
output_interval: 10_00:00:00
restart_interval: 10_00:00:00
start_time: 0001-01-01_00:00:00
stages:
damped_adjustment_1:
run_duration: 10_00:00:00
dt: 02:00:00
btr_dt: 00:06:00
damping: 1.0e-4
simulation:
run_duration: 10_00:00:00
dt: 02:00:00
btr_dt: 00:06:00
# damping omitted => the config default, which is no Rayleigh damping
Nothing about the physics or the time integrators appears here: those come from
[realistic_global_forward] and the mesh’s own overrides, and
load_schedule_stages applies the schedule on top with dataclasses.replace.
Time steps may instead be given per km of mesh minimum resolution
(dt_per_km/btr_dt_per_km), matching the existing ForwardStage support. The
parser computes each stage’s cumulative start/stop time and the shared
restarts/rst.<stop-time>.nc filenames, so the restart chain is deterministic
and not entered by hand. This port renames Compass’ steps to stages and
Rayleigh_damping_coeff to damping, and drops land_ice_flux_mode, which
realistic_global does not yet model.
Four rules keep a schedule honest, all enforced at setup:
Keys are validated against
SCHEDULE_FIELDS— theForwardStagefields minus the ones the restart chain owns — and coerced to each field’s declared type. A renamed or misspelled option raises instead of falling back to the config value, anddo_restart,restart_inandrestart_outcannot be set by a stage at all.start_timeis accepted only in thesharedblock, since it is where the chain begins and each stage’s own start time follows from the durations before it.run_durationis the one key a stage must set, since the chain’s timing follows from it.restart_intervaldefaults to the stage’s ownrun_durationrather than to the config value, because every stage has to write the restart the next one reads.A
restart_intervalmust put the stage’s stop time on MPAS-Ocean’s restart alarm, which is measured from a fixed reference time and not from where the stage starts, and astats_intervalmust be no longer than the stage. Otherwise the restart the next stage needs is never written, or the statistics hold only the record written at startup — and both fail only after the model has run.output_intervalis deliberately not checked: an interval longer than the stage is a legitimate way to say “no 3-D output during the damped stages”, which is what the ported Compass schedules do. Such a stage still writes one record, its initial state for MPAS-Ocean and its final state for Omega, which cannot write on startup.
Implementation: The same conceptual workflow supports either MPAS-Ocean or Omega
Date last modified: 2026/10/28
Contributors: Xylar Asay-Davis, Codex, Claude
Implementation builds on Polaris’ existing model-abstraction machinery,
especially OceanModelStep and the mapping between common YAML-driven
configuration and model-specific MPAS-Ocean or Omega settings.
The dynamic-adjustment code separates:
Schedule parsing and restart sequencing.
Common stage metadata such as duration and cadence (
ForwardStage).Model-specific translation of time-step and damping options (
ForwardStage.model_replacements/bottom_drag_options/omega_damping_replacements).
This separation keeps the workflow portable even though Omega needs different config names and a different subset of controls. Since each task targets a single configured model, no within-task branching is required.
The implementation wires the restart chain end-to-end for MPAS-Ocean, where
the restart stream is both an input and an output stream, so one
filename_template serves both directions and the read side is just
config_do_restart and config_start_time. The start time is stated explicitly
rather than through a restart-pointer file.
The schedule and stage abstraction remain model-agnostic. For Omega, each
stage reads its predecessor’s restart through a StartType and a pointer file,
as described in the forward framework’s design; the chain has been run on all
five unified meshes with an Omega test merge that adds Rayleigh damping. Omega
runs the adjustment with its split-explicit integrator, SplitExplicitRK2, on
the schedules’ split time steps; RK4 would have to advance on the barotropic
step.
Implementation: Dynamic adjustment is decomposed into inspectable restart stages
Date last modified: 2026/10/21
Contributors: Xylar Asay-Davis, Codex, Claude
Each stage lives in its own work directory under
spherical/realistic_global/{mesh_name}/dynamic_adjustment/{stage_name} and
declares:
The restart or initial-condition input it consumes.
The restart file it produces for the next stage.
A stage-local output file for diagnostics or later validation.
The stages share a restarts directory beside them, so a break in the chain is
caught by Polaris before the model launches. The Python driver computes restart
times from cumulative run durations, so the user does not have to provide both a
stage duration and an absolute stop time.
The whole chain — the shared init steps, one Forward step per stage, a
StageCheck after each, summary and viz — is built by
get_realistic_dynamic_adjustment_steps(component, mesh_name, include_viz)
through Component.get_or_create_shared_step, following the same pattern as
get_realistic_init_steps. It returns the stages alongside the steps and
config, because which stage hands off the adjusted state, and what that restart
file is called, both depend on the schedule: stages[-1].restart_out is what a
downstream workflow is after. e3sm/init’s component inputs is such a workflow,
and gets the same step instances rather than a second copy of a chain that costs
days.
Two details are specific to this workflow. Consecutive stages are linked with
Step.add_dependency rather than through their input/output files alone,
because a stage’s restart filename comes from the schedule rather than from the
step, so the wiring is not available inside a step’s constructor the way the
init steps do it; re-adding the same dependency is a no-op, which is what
makes calling the accessor again safe. And each stage’s check is a step of its
own, run immediately after that stage, rather than work the forward step does
after the model exits: a Polaris step is sized for its MPI call, so folding the
check in would hold the model’s whole allocation open to compare a few scalars —
and a stage that is already out of bounds stops the sequence instead of costing
the rest of the job.
Implementation: Adjustment schedules are reusable but easy to tune
Date last modified: 2026/09/24
Contributors: Xylar Asay-Davis, Codex, Claude
The schedules live with the task package, which makes them version-controlled,
easy to review, and easy to tune for a specific resolution family. Six are
checked in: one for each of the five unified meshes, and default.yaml for
everything else. The u-oi30-lr10, u-oi6to18-lr12p5, u-oi6to18-lr25 and
u-oi-so12to30-lr10 schedules are ported from Compass’ ec30to60, rrs6to18
(for both u-oi6to18 meshes) and so12to30; u-oi240-lr240 follows the same
damping ramp on ten-day stages, so that the shape the finer meshes use is
exercised on the cheapest mesh that
has a realistic initial condition.
default.yaml, which the coarse base meshes such as icos240km and qu240km
fall back to, is two stages. That is deliberate: it is a quick check that a mesh
runs at all rather than an adjustment worth keeping, and a mesh that deserves a
real one deserves a schedule of its own.
No automatic tuning procedure was invented, as this section intended. A user
retunes by editing the checked-in YAML or by pointing the schedule config
option at another file before setup.
Implementation: The workflow includes basic validation that the adjustment remained well behaved
Date last modified: 2026/10/21
Contributors: Xylar Asay-Davis, Codex, Claude
Validation ended up split between a per-stage StageCheck step and a final
Summary step, plus the built-in baseline comparison:
A baseline comparison of the final
simulation/output.nc(temperature,salinity,normalVelocity), handled by the forward step’s built-invalidate_class='state'mechanism, as in the forward tasks.Four thresholds per stage, applied by
StageCheckimmediately after that stage: the maximumtemperaturebelowtemperature_max, the minimum abovetemperature_min, the maximumsalinitybelowsalinity_max, and the maximum reported CFL number belowcfl_max. Each reports when the extreme occurred as well as how large it was, which is usually most of the diagnosis, and each is skipped with a log line when the configured model does not report the quantity.Summaryapplies no checks at all. It collects one row of diagnostics per stage, writesdynamic_adjustment_stats.csvand logs the same table, so the summary a user reads and the checks that passed are one calculation rather than two. Its step is namedsummaryrather thanvalidatebecause a Polarisvalidatestep is expected to compare and fail.
The settling heuristic this section listed as item 3 was removed, for the reasons given in the corresponding Algorithm Design section above.
The diagnostics are defined by a METRICS list, each naming the
global-statistics variable it reads in MPAS-Ocean naming, how to reduce that
variable’s time series over the stage, and the output.nc field to fall back to
when the model does not report it. Omega’s statistics are renamed to those names
by open_stage_stats, using the names polaris.ocean.global_stats_names builds
for each model, since mpaso_to_omega.yaml no longer maps statistics pair by
pair; Omega’s pseudo-thickness stands in for layer thickness, as it did in that
map. Metrics with no honest fallback are left blank: a maximum means the same
thing computed either way, a volume-weighted mean does not. Two derived columns,
the mean temperature and salinity change per day, are a conservation check
rather than a settling one — these runs are forced by wind alone with no surface
fluxes, so both should be zero to within machine noise, and u-oi30-lr10
reaches -4e-17 °C/day.
Omega’s GlobalStats covers temperature, salinity, layer thickness, normal
velocity and kinetic energy but has no CFL number or volume-weighted sums. The
reported-CFL column is therefore blank and its threshold check is skipped for
Omega. Polaris separately estimates a conservative horizontal CFL using the
largest absolute normal-velocity extrema, the stage timestep and the smallest
horizontal mesh edge. Because the velocity and edge-length extrema need not be
at the same location, this estimate is an upper bound, not Omega’s CFL, and is
reported for inspection rather than checked against cfl_max. Minimum layer
thickness remains a separate diagnostic; it is not used as a horizontal CFL
length scale. The log says which source each metric came from.
The two tracer thresholds are blow-up detectors, not plausibility bounds, and
they are set above the WOA23 source artifacts rather than above the physics.
NOAA’s January WOA23 analysis contains one bad cell off Sumatra that reaches
35.9 to 36.1 °C in the u-oi6to18 initial conditions and erodes slowly enough
to still be present when the third stage begins, and a Red Sea salinity blob at
1150 m that settles near 42.1 PSU for the rest of the adjustment. A bound placed
at the physics would fail the opening stages of a healthy run; a real blow-up
produces hundreds of degrees or NaN, so there is ample room between the two.
This is also what the sequence-wide startup window exists for.
A viz step plots the same statistics as time series — kinetic energy, maximum
normal velocity, CFL number, tracer extremes, mean tracer change and minimum
layer thickness on one continuous axis, with stage boundaries marked and each
stage labelled with its damping. A summary row cannot distinguish a quantity
that was flat through a stage from one that spiked and recovered, and those call
for different changes to the schedule; the figure can. It belongs to the
standalone task: a workflow that only wants the relaxed restart is not asking
about a completed adjustment. A second figure answers how far the adjustment
moved the ocean from its initial condition, with volume-weighted histograms of
the change in temperature and salinity from the initial state to the end of the
last stage.
The common concept remains “each stage completed and wrote its restart, and the final adjusted state looks reasonable” — with the second half now answered by a person reading a table and a figure, rather than by a threshold pretending to.
Testing
Testing and Validation: A staged dynamic-adjustment workflow can be created from a global initial condition
Date last modified: 2026/09/24
Contributors: Xylar Asay-Davis, Codex, Claude
Unit tests cover schedule parsing, cumulative restart-time calculation, and
error handling for malformed schedules — a missing dynamic_adjustment key, a
missing stages block, a stage that is not a mapping, a missing
run_duration, an unknown key in a stage or in shared, a chain-owned option a
stage tried to set, and start_time outside shared. Others cover the
semantics the format depends on: that a schedule value overrides the config
option of the same name, that a blank value clears an optional field, that
restart_interval defaults to the stage duration, and that stages inherit the
per-mesh overrides, the physics options and the time integrators without
mentioning them.
The two cadence rules get tests of their own, since both otherwise fail only
after the model has run: a restart_interval that misses the stage end raises,
one measured from the fixed reference rather than the stage start is accepted,
and a stats_interval longer than the stage raises while an output_interval
longer than the stage does not.
Running a short multi-stage adjustment on a coarse global mesh remains the
integration test, and is what default.yaml and the u-oi240-lr240 schedule
are for. It is not something a suite can run.
Testing and Validation: The same conceptual workflow supports either MPAS-Ocean or Omega
Date last modified: 2026/10/26
Contributors: Xylar Asay-Davis, Codex, Claude
Model-specific tests confirm that the same staged schedule renders for either
configured model, even though the resulting low-level options are not
identical: the diagnostics summary is built for both, a blow-up is caught for
both, and each model’s stages declare the restart files that model writes. The
differences that must not pass silently get tests of their own — a damped
stage gives Omega its RayleighDamping and an undamped one leaves the group
out, and the statistics filename each model
actually writes is pinned, since Omega’s moves with the statistics interval and
a name that is not found reads as a stage that wrote nothing.
Testing and Validation: Dynamic adjustment is decomposed into inspectable restart stages
Date last modified: 2026/08/11
Contributors: Xylar Asay-Davis, Codex, Claude
Tests verify that the restart chain is consistent — each stage’s restart_out
is the next stage’s restart_in, all in one shared restarts directory — that
a stage in a chain declares both ends of it while a lone stage declares neither,
and that the last stage names the restart a downstream consumer is after.
Because these steps are shared, a second group of tests covers what sharing
means: that two consumers asking for the same mesh get the same step instances,
that every step is registered on the component, that the shared config is reused
rather than rebuilt, that the viz step is created but returned only when
asked, and that configure() rebuilds the stages only when the schedule
actually changed.
Testing and Validation: Adjustment schedules are reusable but easy to tune
Date last modified: 2026/08/11
Contributors: Xylar Asay-Davis, Codex, Claude
Every checked-in schedule is exercised, not just one, so that a change to the
parser or to the model-option mapping cannot silently break any of them. The
tests assert the properties that make a schedule an adjustment rather than an
arbitrary sequence of runs: each unified mesh has the expected number of stages,
the damping ramps monotonically down, the final stage is undamped, and every
stage writes statistics within its own duration. A mesh with no file of its own
falls back to default.yaml, and that fallback chains correctly too.
Testing and Validation: The workflow includes basic validation that the adjustment remained well behaved
Date last modified: 2026/10/21
Contributors: Xylar Asay-Davis, Codex, Claude
Regression testing includes loose threshold checks and a baseline comparison on a few key fields, to catch obvious failures such as numerical instability, missing restart chaining, or grossly unphysical state variables.
The tests around those thresholds are mostly about which samples a stage is judged on, because that is where the checks are easy to get wrong: that the sample written before a stage’s first time step is excluded, that an extreme after it is still caught, that the startup window skips only the stages it actually reaches, that a sample landing exactly on the window’s edge is excluded, that a stage left with nothing to judge is reported rather than silently passed, and that the CFL check deliberately watches inside the window the tracer checks skip. A further pair confirms that a blow-up in the middle of a stage is caught from the statistics — the case an end-of-stage field would miss — and that the summary applies the same windows the checks do, so the CSV and the checks cannot disagree.
This section previously asked for a test that the last few stages show tapering
behavior in a kinetic-energy metric. There is instead a test asserting that
Summary does not judge the kinetic energy, for the reasons in the Algorithm
Design section: three samples of a quantity that is not comparable across stages
cannot distinguish a healthy adjustment from a runaway, and every attempt to
make them failed healthy runs. Whether a schedule is settling is read from the
diagnostics table and the viz figure, whose own tests confirm that the series
is plotted, that stages without statistics are skipped, and that stage labels
stay legible when a schedule opens with stages far shorter than the axis.