Skip to content
Get started

Continuum laws and boundaries

Standard library

The bundled Eqiora.Solid.LinearElasticity and Eqiora.Fluid.Incompressible packages contain reusable volume laws and mechanical boundary interfaces. You bind your own fields to them and supply a condition on each exterior face. Both examples below compile as ordinary package imports.

elastic-body.eqi
import Eqiora.Solid.LinearElasticity.linear_elasticity as solid;
model ReferenceElasticBody() {
domain body = box(0, 1, 0, 1);
domain left = boundary(body, axis = 0, side = lower);
domain right = boundary(body, axis = 0, side = upper);
domain bottom = boundary(body, axis = 1, side = lower);
domain top = boundary(body, axis = 1, side = upper);
variable displacement: vector<m, 2> on body in smooth;
variable load_potential: Pa on body;
relation unloaded on body { load_potential = 0[Pa]; }
parameter mu: Pa = 3;
parameter lambda: Pa = 2;
instance balance: solid.IsotropicBalanceWithPotential2d(
body = body, displacement = displacement,
load_potential = load_potential, mu = mu, lambda = lambda
);
instance elasticity: solid.IsotropicMechanicalInterface2d(
body = body, exterior = boundaries(left, right, bottom, top),
displacement = displacement, mu = mu, lambda = lambda
);
instance clamp: solid.FixedDisplacement2d(body = body, face = left);
instance free_right: solid.ZeroTraction2d(body = body, face = right);
instance free_bottom: solid.ZeroTraction2d(body = body, face = bottom);
instance free_top: solid.ZeroTraction2d(body = body, face = top);
connect elasticity.mechanical[boundary = left], clamp.mechanical;
connect elasticity.mechanical[boundary = right], free_right.mechanical;
connect elasticity.mechanical[boundary = bottom], free_bottom.mechanical;
connect elasticity.mechanical[boundary = top], free_top.mechanical;
}

The square is clamped on the left and traction-free elsewhere. Its volume load is zero, so its equilibrium displacement is zero. The Lamé parameters are mu = 3 Pa and lambda = 2 Pa. The boundary conditions act on the same displacement field as the volume equations.

Component in Eqiora.Solid.LinearElasticity.linear_elasticity Use
IsotropicBalanceWithPotential2d Small-strain isotropic equilibrium with Lamé parameters mu and lambda
IsotropicMechanicalInterface2d Displacement trace and outward elastic traction on the complete exterior
FixedDisplacement2d Zero displacement on one face
ZeroTraction2d Zero traction on one face

The balance uses stress 2με+λ tr(ε)I2\mu\varepsilon+\lambda\,\mathrm{tr}(\varepsilon)I. load_potential is a scalar with units of pressure whose gradient gives the body force; it is neither a boundary pressure nor a general vector force. The interface’s QuasistaticMechanicalBoundary connector pairs displacement with traction, so a connected terminal shares the body’s displacement and carries the opposite traction.

For plane strain, derive the Lamé parameters from Young’s modulus EE and Poisson’s ratio ν\nu as μ=E/[2(1+ν)]\mu=E/[2(1+\nu)] and λ=Eν/[(1+ν)(1−2ν)]\lambda=E\nu/[(1+\nu)(1-2\nu)]. For plane stress, use the effective in-plane value λ=Eν/(1−ν2)\lambda=E\nu/(1-\nu^2) instead.

Read strain and stress for the constitutive derivation and the mixed-boundary square for a loaded calculation.

stokes.eqi
import Eqiora.Fluid.Incompressible.incompressible as fluid;
model ReferenceStokes() {
domain body = box(0, 4, 0, 1);
domain left = boundary(body, axis = 0, side = lower);
domain right = boundary(body, axis = 0, side = upper);
domain bottom = boundary(body, axis = 1, side = lower);
domain top = boundary(body, axis = 1, side = upper);
variable velocity: vector<m / s, 2> on body in smooth;
variable pressure: Pa on body in h1;
variable force_potential: Pa on body;
variable inlet_speed: m / s on body in h1;
relation inputs on body {
force_potential = 0[Pa];
inlet_speed = 1[m / s];
}
parameter viscosity: Pa * s = 1;
instance flow: fluid.SteadyStokesWithPotential2d(
body = body,
velocity = velocity, pressure = pressure,
force_potential = force_potential, dynamic_viscosity = viscosity
);
relation inlet on left {
trace(velocity) + normal(isotropic_lift(inlet_speed)) = 0;
}
relation outlet on right {
normal(2 * viscosity * symmetric_part(grad(velocity))
- isotropic_lift(pressure)) = 0;
}
relation lower_wall on bottom { trace(velocity) = 0; }
relation upper_wall on top { trace(velocity) = 0; }
}

The inlet specifies inward normal speed, the top and bottom walls impose zero velocity, and the outlet imposes zero total traction. The model contains no advective or inertial term: use it when viscous stresses dominate.

SteadyStokesWithPotential2d supplies momentum balance and incompressibility. The caller supplies the four boundary relations here. On the left, the outward normal points left, so the plus sign in the inlet equation gives rightward flow. At the outlet, normal(stress) = 0 sets the total traction to zero; it does not set the pressure to zero.

For port-based boundary composition, the same module supplies NewtonianMechanicalInterface2d, binding body, the complete exterior, velocity, pressure, and dynamic_viscosity. Its ports use the VelocityTractionBoundary connector from Eqiora.Mechanics.Interfaces. That package supplies ZeroVelocity2d and ZeroTraction2d terminal components. Add it as a direct dependency when importing its declarations into your own source.

Stokes flow and boundaries derives these conditions. Computing incompressible flow continues to mesh and solver choices.

Save the desired model as model.eqi, then create its local project:

python
from pathlib import Path
import eqiora
project = Path("continuum")
(project / "src").mkdir(parents=True, exist_ok=True)
(project / "src/main.eqi").write_text(Path("model.eqi").read_text())
(project / "eqiora.toml").write_text(
'[package]\nname = "org.example.Continuum"\nversion = "0.1.0"\nentry = "main"\n'
)
store = Path("package-store")
store.mkdir(exist_ok=True)
resolution = eqiora.add_bundled_dependency(
project, store, "Eqiora.Solid.LinearElasticity", version="0.6.0"
)
model = eqiora.compile_package(store, resolution, entry="ReferenceElasticBody")

For the Stokes example, use "Eqiora.Fluid.Incompressible" and entry "ReferenceStokes"; its package version is also "0.6.0". add_bundled_dependency installs the package sources and writes the lock. To run the model, add a mesh and a numerical method as described in the modeling guide.

The repository source package Eqiora.Fluid.InertialStokes defines the separate InertialStokesWithPotential2d volume component:

inertial_stokes.eqi — library declaration
public component InertialStokesWithPotential2d(
support body: volume(ambient_dimension = 2),
state velocity: vector<m / s, 2> on body,
variable pressure: kg / (m * s ^ 2) on body,
variable force_potential: kg / (m * s ^ 2) on body,
parameter density: kg / m ^ 3,
parameter dynamic_viscosity: kg / (m * s)
) {
relation momentum on body {
density * derivative(velocity)
- div(
2 * dynamic_viscosity * symmetric_part(grad(velocity))
- isotropic_lift(pressure)
) - grad(force_potential) = 0;
}
relation incompressibility on body {
div(velocity) = 0;
}
}

It binds a velocity state, pressure and force-potential fields, density, and dynamic viscosity. The time derivative adds inertia; there is still no velocity-advection term. Supply initial velocity, boundary conditions, pressure reference where needed, and a time method when building a complete problem around this law.

For a time-dependent advective flow example, see cylinder wakes. Eqiora.Fluid.Incompressible and Eqiora.Solid.LinearElasticity also contain three-dimensional dynamic volume and interface declarations.

The repository’s Eqiora.Solid package has plane-strain and plane-stress components written in terms of Young’s modulus and Poisson’s ratio, with typed material properties and field-driven boundaries. Eqiora.Fluid has a combined steady Stokes component and velocity, pressure, and traction terminals. They are useful examples of how to combine the underlying equations.

Eqiora.Solid, Eqiora.Fluid, and Eqiora.Fluid.InertialStokes are not bundled, so add_bundled_dependency does not accept them.

Open the solid equations · Open the fluid equations