Time & Timestep
On this page
Time & Timestep Management
Set the timestep used by the integrator or direct plan execution with:
set_timestep(ctx, dt)
Read the accumulated simulation time, timestep, and step index with:
get_time(ctx) -> time
get_timestep(ctx) -> dt
get_step_index(ctx) -> step_index
On-step Callbacks
Register a callback to be invoked after each successful step:
on_step(ctx, fn)
Note: Manual Step Hook
on_stepis invoked bystepafter a successful step, including the cases wherestepinternally delegates to the scheduler for a single step. Long-running scheduler loops started withrundo not invoke the Lua hook.
Step Metrics
After each successful step, the runtime records metrics including accepted/requested timestep, RMS error, dirty/stable writes, and active warp mask. Access these via step_metrics_latest and step_metrics_history.
step_metrics_latest(ctx) -> metrics
step_metrics_history(ctx, [max_count]) -> metrics_array
The metrics table has the following fields:
| Field | Type | Description |
|---|---|---|
step_index |
integer |
The zero-based step counter at the time of the record. |
requested_dt |
double |
The timestep requested at the start of the step. |
accepted_dt |
double |
The timestep accepted at the end of the step. |
next_dt |
double |
The suggested next timestep for adaptive integrators. |
rms_error |
double |
The RMS error estimate for the step. |
step_wall_ns / step_wall_ms |
integer / double |
Total wall time for the step. |
integrator_wall_ns / integrator_wall_ms |
integer / double |
Wall time spent inside integrator work. |
operator_wall_ns / operator_wall_ms |
integer / double |
Wall time spent in direct operator execution. |
dirty_writes |
integer |
Number of fields/operators that wrote data this step. |
stable_writes |
integer |
Number of fields/operators that wrote stable data this step. |
active_warp_mask |
integer |
Bitmask of active warps during this step. |
step_metrics_history(ctx, max_count) is capped internally at SIM_STEP_METRIC_HISTORY; larger requests are truncated to that history size.
Timestep Heuristics Preview
Query the scheduler’s adaptive timestep recommendation (if enabled):
timestep_decision(ctx) -> decision
The decision table includes:
| Field | Type | Description |
|---|---|---|
kind |
string |
keep, shrink, or expand. |
kind_value |
integer |
Numeric enum value for the decision. |
suggested_dt |
double |
Proposed timestep if the decision is applied. |
enabled |
boolean |
Whether heuristics are enabled (enable_timestep_heuristics). |
available |
boolean |
true when a preview decision is available for the current context. |
Note: Decision Availability
availableisfalseuntil the scheduler has recorded step metrics (and when heuristics are disabled or the scheduler is not active).
Integrator Controls 🔄
Attach an integrator to the context with set_integrator, then control its behavior with the following functions:
set_integrator_adaptive(ctx, enabled)
set_integrator_stochastic(ctx, enabled)
set_integrator_stochastic_strength(ctx, strength)
set_integrator_noise(ctx, noise_type)
set_integrator_seed(ctx, seed)
integrator_info(ctx) -> info_table
The info_table returned by integrator_info includes:
| Field | Type | Description |
|---|---|---|
name |
string |
The integrator’s name (e.g., “rkf45”). |
adaptive_enabled |
boolean |
Whether adaptivity is enabled. |
enable_stochastic |
boolean |
Whether stochastic perturbations are enabled. |
stochastic_strength |
double |
The strength of stochastic perturbations. |
noise |
string |
The type of noise applied (e.g., “gaussian”). |
random_seed |
integer |
The RNG seed currently in use. |
min_dt |
double |
The minimum allowed timestep for adaptive integrators. |
max_dt |
double |
The maximum allowed timestep for adaptive integrators. |
tolerance |
double |
The error tolerance for adaptive integrators. |
safety |
double |
The safety factor for adaptive timestep selection. |
current_dt |
double |
The current timestep being used by the integrator. |
Reading Clocks & Metrics 🔍
local ok = ooc.step(ctx)
if ok then
local t = ooc.get_time(ctx)
local metrics = ooc.step_metrics_latest(ctx)
if metrics then
ooc.log("t=%.4f dt=%.4f rms=%.2e writes=%d",
t, metrics.accepted_dt, metrics.rms_error, metrics.dirty_writes)
end
end
-- Grab a rolling window (up to SIM_STEP_METRIC_HISTORY)
for _, m in ipairs(ooc.step_metrics_history(ctx, 32)) do
-- m has the same shape as metrics above
end
sleep(seconds) is available when you need to yield control in GUI/evented loops without shutting down the context.
On-step Hooks for Sweeps/Logging 🪝
local t = 0
ooc.on_step(ctx, function(context)
t = t + 1
local s = math.sin(t * 0.000005)
ooc.operator_param_set(ctx, 1, "wavenumber", s)
end)
Use this for lightweight parameter sweeps or GUI-driven probes. Because the plan is invalidated each step, avoid heavy work inside the callback; keep it to parameter updates or logging.
Typical Drive Loop 🔄
- Seed the timestep with
set_timestep(or leave the default if your integrator supplies one). - Attach an integrator and optionally enable adaptivity/noise policies.
- Step with
step, readget_timeand metrics, and adjust parameters mid-run if needed.