Evaluating ODE Models#

This page explains how to run inference (evaluation) on trained NeurEco ODE models. ODE models are dynamical systems that require understanding of initialization to produce accurate simulations.

Understanding ODE Initialization#

Unlike static models, ODE models maintain internal state and produce trajectories that evolve over time. To simulate a trajectory, the model needs to know where to start — this is called initialization.

NeurEco ODE supports two initialization modes:

  1. Explicit initialization (Recommended): You provide the initial state of the system

  2. Steady-state initialization (Default): The model starts from its own steady state for the first excitation values

Initialization Modes#

Mode 2: Steady-State Initialization (Default)#

If no initialization is provided, NeurEco computes the steady state (equilibrium) of the learned model for the first excitation values of the sequence, and the simulation starts from it.

This equilibrium is found for the excitation values at the first time of the sequence. It is the steady state given at the build only when these values are that steady state:

  • First excitation values equal to steady_state_exc: the simulation starts from the given steady state, and the first predicted outputs equal steady_state_out.

  • Other first excitation values: NeurEco searches the model’s equilibrium for them, starting from the given steady state (or, for a model built without one, from its equilibrium at the input normalization shift). This equilibrium was learned, not given at the build: the first predicted outputs are the model’s, and nothing guarantees they match the real system.

This mode:

  • Is simpler (no initialization data needed)

  • Assumes the system starts at rest, in the steady state that matches its first excitation values

  • Starts from a known point only when the first excitation values are the steady state given at the build (see Using Steady-State Constraints)

If no steady state can be computed for the first excitation values, which can happen with or without a steady state given at the build, the evaluation starts from the initial state learned for the training trajectory whose first excitation values are closest. The log says so, as an information message when the model was built without a steady state and as a warning otherwise. To set the starting point yourself, use explicit initialization (init_outputs).

Evaluating an ODE Model#

Loading a Model

  1. Open your project or load a saved model

  2. Switch to the Evaluation panel

Providing Evaluation Data

  1. Click + next to Evaluation files

  2. Select your input (excitation) file

  3. Optionally select an output file (for comparison/metrics)

Initialization Options

Using steady-state initialization:

  • Simply run evaluation without providing initialization data

  • The model starts from its own steady state for the first excitation values (see Mode 2 above)

Using explicit initialization:

  1. Provide an output file that includes initial values

  2. Use the Initialization samples slider to specify how many initial time steps to use

  3. The model uses these points to initialize, then simulates forward. The prediction starts at the last sample of the initialization interval (the interval and the prediction share that sample) and runs to the end of the file.

Running Evaluation

  1. Click Evaluate

  2. View results in the plot panel

  3. Use the Sample slider to browse through sequences

  4. Compare predictions (blue) with reference (orange) if provided

Metrics

Switch to the Metrics panel to see:

  • L2 relative error for each output

  • Per-sequence error breakdown

  • Training vs. validation vs. test performance

Each file of the Metrics list offers two initializations. Default Initialization, the default, initializes every checkpoint from the first samples of the file, with the checkpoint’s own number of initialization time steps (the Time steps for initialization editor shown over the file changes this number). Steady State Initialization starts from the model’s steady state for the first excitation values (Mode 2 above).

Method Reference#

predictions = model.evaluate(
    excitations=None,        # Input array(s), time in column 0
    init_excitations=None,   # Initialization inputs (required for explicit init), time in column 0
    init_outputs=None,       # Initialization outputs (required for explicit init), time in column 0
    *,
    time=None,               # Deprecated: separate time array(s)
    init_time=None,          # Deprecated: separate initialization time
)

Parameters:

Parameter

Required

Description

excitations

Yes

Input array(s) with time in the first column. Shape (n_samples, 1 + n_inputs) or a list of such arrays.

init_excitations

No

Initialization input values, time in the first column (required for explicit init)

init_outputs

No

Initialization output values, time in the first column (required for explicit init)

time

No

Deprecated (keyword-only). Separate time array(s); emits a DeprecatedParameterWarning and returns predictions without a leading time column.

init_time

No

Deprecated (keyword-only). Separate initialization time values.

Returns:

  • Single sequence: NumPy array of shape (n_samples, 1 + n_outputs), with time in the first column

  • Multiple sequences: List of such NumPy arrays

Note

When excitations carries the time in its first column, the returned predictions are time-first (time in column 0). The deprecated separate-time form returns predictions without a leading time column.

Scripts written for NeurEco 4.x that call evaluate(time, excitations, init_time, init_excitations, init_outputs) with positional arguments still run: this form emits a DeprecatedParameterWarning and also returns predictions without a leading time column.

Using Known Initial Conditions from Data#

When you have reference data and want to evaluate starting from a known point:

import numpy as np
from NeurEco import NeurEcoDynamic as Dynamic

# Load model
model = Dynamic.ODE()
model.load("my_ode_model.ernn")

# Reference data (time in column 0)
time_full = np.linspace(0, 10, 1000)
exc_full = np.column_stack([time_full, np.random.randn(1000, 3)])
out_full = np.column_stack([time_full, np.random.randn(1000, 2)])  # Known ground truth

# Use first N points as initialization
n_init = model.get_number_of_init_tsteps()

# Both init arrays keep their time in the first column
init_exc = exc_full[:n_init]
init_out = out_full[:n_init]

# Evaluate from the last initialization point onward
# Note: The last init point is the first prediction point (overlap)
eval_exc = exc_full[n_init - 1:]

# eval_exc / init_exc / init_out all carry time in their first column;
# predictions are returned time-first.
outputs = model.evaluate(
    eval_exc,
    init_excitations=init_exc,
    init_outputs=init_out,
)

# Compare to ground truth (starting from the same point, also time-first).
# compute_error takes outputs only, so drop the leading time column from both.
ground_truth = out_full[n_init - 1:]
error = model.compute_error(outputs[:, 1:], ground_truth[:, 1:])
print(f"L2 relative error: {error:.6f}")

Retrieving Steady-State Values#

To inspect the steady-state values learned by the model:

steady_inputs = model.get_steady_input()
steady_outputs = model.get_steady_output()

print(f"Steady-state inputs: {steady_inputs}")
print(f"Steady-state outputs: {steady_outputs}")

Model Information#

# Number of inputs and outputs
print(f"Inputs: {model.get_input_count()}")
print(f"Outputs: {model.get_output_count()}")

# Number of hidden states
print(f"Hidden states: {model.get_state_count()}")

# Initialization steps required
print(f"Init steps: {model.get_number_of_init_tsteps()}")

Best Practices#

  1. Match time step: The evaluation time step must match the training time step

  2. Use explicit initialization when possible: For best accuracy, provide known initial conditions

  3. Verify initialization length: Use get_number_of_init_tsteps() to determine how many initialization points are needed

  4. Check steady state: If using steady-state initialization, verify the learned steady state matches your expectations

Next Steps#