Skip to content
Get started

Get started

Run a small model, then change it and see the difference. You need two files and a Python environment. Install the same source revision as this page so the parser and downloaded model agree; no mesh generator or editor extension is needed.

These commands use Linux x86-64 and ordinary-GIL CPython 3.13. Install Git, Rust stable with Cargo, and a C compiler/linker before building the Python package from source. On Ubuntu, build-essential provides the compiler and linker.

Install uv if you do not have it, then open a terminal in a new working folder:

Install the page's source revision
mkdir first-eqiora-model
cd first-eqiora-model
git init eqiora-source
git -C eqiora-source remote add origin https://github.com/nkiyohara/eqiora.git
git -C eqiora-source fetch --depth 1 origin 9f45b2733cb46f3740aa3d31f99542411bad6c3f
git -C eqiora-source checkout --detach FETCH_HEAD
uv venv --python 3.13
uv pip install --python .venv/bin/python --reinstall-package eqiora ./eqiora-source

The checked-out revision owns both the installed package and the model shown below. Building takes longer than installing a prebuilt wheel. Keep eqiora-source for the Reference examples.

Keep the following files in this folder, beside .venv. No shell activation is needed: each run below explicitly selects that environment.

Let a dimensionless quantity xx start at 1 and decay at rate k=1s1k=1\,\mathrm{s}^{-1}:

dxdt+kx=0,x(0)=1.\frac{\mathrm{d}x}{\mathrm{d}t}+kx=0,\qquad x(0)=1.

The solution is x(t)=exp(kt)x(t)=\exp(-kt). After one second, predict x(1)=exp(1)0.367879x(1)=\exp(-1)\approx0.367879—about 37% of the initial value.

Download decay.eqi, or copy this complete source into a file named decay.eqi:

decay.eqi
// A minimal implicit ODE: x decays at the rate supplied by the user.
model decay() {
// `x` is dimensionless and starts at 1. `rate` has inverse-time units.
state x: 1;
initial { x = 1; }
parameter rate: 1 / s = 1;
// Eqiora writes the evolution law as a residual equal to zero.
relation flow {
derivative(x) + rate * x = 0;
}
}

The .eqi file describes the model. state x declares the evolving unknown and initial { x = 1; } sets its initial condition, parameter rate has inverse-second units, and the relation states an equation with two ordered sides of an equality. The numerical method does not belong in this file.

Download run.py, or copy this complete script into run.py in the same folder:

run.py
"""Run the decay model shared by Get started and the ODE lesson."""
from __future__ import annotations
import argparse
from pathlib import Path
import eqiora
OUTPUT_TIMES_S = (0.25, 0.5, 1.0)
def solve(source_path: Path) -> tuple[tuple[float, float], ...]:
"""Return the requested (time in seconds, dimensionless value) samples."""
model = eqiora.compile(path=source_path)
field = model.field(model.field_ids[0])
plan = eqiora.resolve(
model,
temporal=eqiora.time.Tsitouras45(
initial_step_s=0.01,
relative_tolerance=1.0e-9,
absolute_tolerances={field: 1.0e-11},
),
)
result = eqiora.run(
plan,
state=eqiora.State.initial(plan),
until_s=OUTPUT_TIMES_S[-1],
output_times_s=OUTPUT_TIMES_S,
)
series = result.series(field)
times = series.time.numpy()
values = series.values.numpy()
return tuple(
(float(time_s), float(value))
for time_s, value in zip(times, values, strict=True)
)
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("model", nargs="?", type=Path, default=Path("decay.eqi"))
args = parser.parse_args()
for time_s, value in solve(args.model):
print(f"t={time_s:.2f}, x={value:.10f}")
if __name__ == "__main__":
main()

The script compiles decay.eqi, chooses an adaptive time method, starts from the model’s initial state and requests three observations. The returned Result contains a time series selected by the model’s field handle. The two NumPy arrays hold times in seconds and the corresponding dimensionless values.

Terminal windowbash
uv run --no-project --python .venv/bin/python python run.py

You should see values close to:

text
t=0.25, x=0.7788007829
t=0.50, x=0.6065306597
t=1.00, x=0.3678794412

The last line agrees with the hand prediction. The result is printed in the terminal; this small script does not create a plot or save a result file.

In decay.eqi, change just the rate declaration to:

eqiora
parameter rate: 1 / s = 2;

Before rerunning, predict x(1)=exp(2)0.135335x(1)=\exp(-2)\approx0.135335: doubling the rate makes the quantity decay faster. Run the same command and script again. Its last line should now be close to t=1.00, x=0.1353352833.

You changed the model, not the time method. Restore rate to 1 when following the ODE lesson.

  • uv: command not found: install uv using its linked instructions, reopen the terminal and check uv --version.
  • Source build fails: check cargo --version and cc --version, then repeat the uv install command. Use CPython 3.13 and the checked-out source revision.
  • Wrong Python or missing eqiora: run uv run --no-project --python .venv/bin/python python -c "import eqiora; print(eqiora.__version__)". A version number alone does not identify a source build. Check git -C eqiora-source rev-parse HEAD against the revision in the install command, then reinstall from that checkout. Use the same folder and environment for each run.
  • Model file not found: keep decay.eqi beside run.py and run from their folder, or pass its path: python run.py path/to/decay.eqi inside the selected environment.
  • A source diagnostic: misspelling rate as missing_rate in the relation produces EQ0603: unresolved expression symbol. Correct the name to match the declaration. Changing the rate’s unit to m instead produces an addition/subtraction dimension mismatch: the two terms must both have inverse-time units.

Capabilities describes which problem classes and numerical methods are available when you move beyond this example.