Skip to content
Get started

Equations and state

Language overview

eqi
relation ohm { voltage = resistance * current; }

A relation constrains quantities. It is not an assignment or a sequence of commands. Both sides must have matching dimensions and shapes. A relation may contain several equations, all of which hold simultaneously. Use on body for a spatial relation and at tick for a relation activated by a periodic clock.

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;
}
}

derivative(x) denotes the time derivative of a continuous state. Here the model has the solution x(t)=exp⁡(−t)x(t)=\exp(-t) with the default rate of 1/s. initial supplies the mathematical initial equation; a solver’s initial guess or time step does not replace it. A spatial block can name its support: initial on body { u = 1 + coordinate(0)/1[m]; }. Python authoring uses component.initial((u, profile), on=body). The existing coordinate axis and support checks apply; this does not request a separate initialization solver.

The ODE lesson continues through State.initial(plan) and execution. To continue an existing run, use its accepted State rather than reinitializing the model at each output time.

A law gives storage, outward flux, and source terms. A steady law has no storage term. The following complete component uses Fourier conduction and four fixed boundary temperatures:

HeatedBody — steady conduction
/// Steady heat conduction on a unit square cross-section, per unit depth.
/// All four exterior faces are held at 300 K; this Component has no time evolution.
public component HeatedBody(
support body: volume(ambient_dimension = 2),
support x_lower: boundary(parent = body),
support x_upper: boundary(parent = body),
support y_lower: boundary(parent = body),
support y_upper: boundary(parent = body),
parameter conductivity: W / (m * K),
parameter heating: W / m^3
) {
variable temperature: K on body in h1;
relation prescribed_x_lower on x_lower { trace(temperature) = 300[K]; }
relation prescribed_x_upper on x_upper { trace(temperature) = 300[K]; }
relation prescribed_y_lower on y_lower { trace(temperature) = 300[K]; }
relation prescribed_y_upper on y_upper { trace(temperature) = 300[K]; }
law heat_balance on body {
flux -conductivity * grad(temperature);
source heating;
}
form weak_heat for heat_balance {
test w: 1 for temperature zero_on x_lower, x_upper, y_lower, y_upper;
integrate(body, dot(grad(w), conductivity * grad(temperature)))
= integrate(body, w * heating);
}
}

Read its flux as q=−k∇T\mathbf q=-k\nabla T and source as volumetric heating. The local steady balance is ∇⋅q=Q\nabla\cdot\mathbf q=Q. form weak_heat for heat_balance attaches a weak form to that physical law. test w: 1 for temperature zero_on ... associates a test field with temperature and makes it vanish on the prescribed-temperature boundaries. integrate and dot express the resulting integral equation.

For time-dependent storage, the same source provides:

TransientHeatedBody — heat storage and conduction
/// Heat storage and conduction with complete constant initial and boundary data.
/// The caller supplies positive volumetric capacity; the reference temperature is 300 K.
public component TransientHeatedBody(
support body: volume(ambient_dimension = 2),
support x_lower: boundary(parent = body),
support x_upper: boundary(parent = body),
support y_lower: boundary(parent = body),
support y_upper: boundary(parent = body),
parameter conductivity: W / (m * K),
parameter heating: W / m^3,
parameter capacity: J / (m^3 * K)
) {
state temperature: K on body in h1;
initial { temperature = 300[K]; }
relation prescribed_x_lower on x_lower { trace(temperature) = 300[K]; }
relation prescribed_x_upper on x_upper { trace(temperature) = 300[K]; }
relation prescribed_y_lower on y_lower { trace(temperature) = 300[K]; }
relation prescribed_y_upper on y_upper { trace(temperature) = 300[K]; }
law heat_balance on body {
storage capacity * temperature;
flux -conductivity * grad(temperature);
source heating;
}
}

The balance is now ∂t(cT)+∇⋅q=Q\partial_t(cT)+\nabla\cdot\mathbf q=Q with constant volumetric heat capacity cc. The initial field is 300 K everywhere. Follow the thermal model walkthrough for package construction and execution, or weak forms and finite elements for the derivation.

Expression Meaning
grad(temperature) Spatial temperature gradient
div(velocity) Divergence of a velocity field
symmetric_part(grad(displacement)) Infinitesimal strain tensor
trace(temperature) Temperature restricted to the relation’s boundary
normal(stress) Stress contracted with the parent-outward normal, giving traction
isotropic_lift(pressure) Pressure times the identity tensor
dot(a, b) Inner product of compatible vectors

The support and tensor shapes must match the operation. See continuum components for stress and boundary examples.

clocked.eqi
model Counter() {
clock tick = periodic(1[s] / 10, phase = 0[s] / 1);
state memory: 1 at tick;
initial { memory = 0; }
relation advance at tick {
next(memory) - pre(memory) - 1 = 0;
}
}

The clock period is exactly 1/10 second, with phase zero. pre(memory) is the value before a tick; next(memory) is the candidate updated value. The first tick advances memory from 0 to 1. The update’s equations are simultaneous.

pre and next require a state on that exact clock; use derivative for continuous state. Equal clock periods do not make independently declared clocks interchangeable. Sampled controls provides reusable delay and integration components and an executable project.

eqi
model Contact(parameter load: N = 0) {
variable gap: m;
variable force: N;
relation contact {
2[N/m] * gap - force = load;
complementarity(0[m] <= gap, force >= 0[N]);
inequality(gap <= 4[m]);
}
}

The complementarity condition requires nonnegative gap and force with at least one equal to zero. A positive gap therefore has zero contact force; a positive contact force has zero gap. The inequality adds an upper bound on the gap.

inequality uses non-strict <= or >= between compatible real scalars. complementarity takes two explicit nonnegativity predicates; its two operands may have different dimensions, as above, but share support.

Execution handles finite, non-spatial problems whose active sets are affine. The Plan sets the constraint tolerances, in coherent SI units, and a limit on branch enumeration. No penalty or smoothing is added. Spatial contact and friction are not supported.

Heat component source · Composition