Code structure
In one minuteA map of the package — which module owns which concept, how data is laid out in memory, and the conventions that the numerical kernels, the solver and the service share.
One Python package, src/gyre, in five layers. Numerics (basis, mesh, physics,
dg, implicit, linear, functionals) are pure JAX kernels. The discipline
(discipline, error, adapt, deform) turns them into “solve, outputs, derivatives”.
Cases and execution (cases, runner, io, cli) describe an analysis as data and run
it. Delivery (service, agent, client, pipeline) exposes the same execution path
over HTTP, MCP and YAML pipelines. Evidence (verify, docsite) produces the
verification records and this site. Everything above the discipline calls
runner.run_case, so the interfaces cannot drift apart.
Module map#
| Module | Owns |
|---|---|
gyre.basis |
LGL nodes and weights, derivative and interpolation matrices, SBP operators, pair tables, p-transfer operators (NumPy, set-up time) |
gyre.mesh |
Mesh (global high-order nodes, element→node map, boundary tags), structured-block builder, face connectivity and orientation |
gyre.meshgen |
generators: airfoil_omesh, annulus, bump_channel, flat_plate, sphere_shell (cubed sphere), box, spanwise extrusion |
gyre.meshio |
mesh files: Gmsh MSH reader (2.2 and 4.1, ASCII) and writer (2.2), the NPZ format, validation, inspection, lookup of the file a case names |
gyre.physics |
compressible Euler/Navier–Stokes kernels: variable sets, two-point and interface fluxes (classical and entropy stable), viscous flux, flow parameters |
gyre.turbulence |
negative Spalart–Allmaras closure: model functions, source terms, boundary values, wall distance to curved walls as differentiable foot-point tables, manufactured solutions |
gyre.dg |
Discretization, differentiable geometry, boundary conditions, the residual kernel |
gyre.timestep |
explicit low-storage Runge–Kutta (verification) |
gyre.linear |
flexible GMRES in JAX control flow |
gyre.implicit |
Hierarchy (p-multigrid, block inverses, line factors, forward/transposed solves), SteadySolver |
gyre.lines |
lines of strongly coupled elements of an anisotropic mesh and the colouring used to assemble their coupling blocks (NumPy only) |
gyre.functionals |
surface integration from residual fluxes, force/moment/heat functionals, nodal loads, distributions |
gyre.deform |
inverse-distance-weighted mesh deformation: a stored matrix for small meshes, matrix-free with a hand-written transpose above entries |
gyre.discipline |
FlowDiscipline: the MDO contract |
gyre.error |
adjoint-weighted-residual error estimation |
gyre.adapt |
output-driven order selection: uniform p-enrichment until the error estimate of an output meets a tolerance |
gyre.mms |
manufactured solutions with AD-generated forcing |
gyre.cases |
CaseSpec (pydantic), presets, Case |
gyre.runner, gyre.io |
end-to-end execution record; checkpoints, VTK, browser payloads |
gyre.identity |
the one definition of “which code is this”: version, commit, and what makes a tree dirty; stamps results, verification records, pipeline records and the documentation |
gyre.service.* |
API application, job manager, worker, sessions, mesh store, pipeline runs, limits, host validation, response schemas, store |
gyre.agent.* |
MCP server (mounted or standalone proxy) |
gyre.client |
HTTP client and RemoteDiscipline |
gyre.pipeline.* |
pipeline engine and compute tasks |
gyre.verify.* |
verification studies and suite runner |
gyre.docsite.* |
documentation site builder |
gyre.integrations.* |
optional framework adapters (OpenMDAO) |
Data layout#
| Quantity | Shape | Notes |
|---|---|---|
state U |
(nvar, K, n, n[, n]) |
variables first; n = p + 1 nodes per direction |
geometry x |
(dim, K, n, …) |
solution nodes |
metrics Ja |
(dim, dim, K, n, …) |
Ja[a, b] = component b of |
| face data | (…, K, F, nq) |
F = 2·dim faces, nq = n^(dim-1) face nodes |
neighbour gather plus |
(K, F, nq) int |
flat index into a (K·F·nq) face array |
| block inverses | (K, bs, bs) |
bs = nvar · n^dim |
Local face f = 2a + s is the face normal to reference direction a at (s = 0)
or (s = 1). Face-node arrays keep the remaining reference directions in ascending order;
the neighbour’s ordering is reconciled by a permutation encoded in plus.
Neighbours are found topologically: each face is keyed by the sorted global ids of its corner
geometry nodes (after mapping periodic images to a common id). The relative orientation of two
matching faces — one of two in 2-D, one of eight in 3-D — is found by comparing their geometry
node ids under each index symmetry, and the result is stored as three booleans
(transpose, flip, flip). The gather index for any polynomial degree is generated from those
booleans, so every p-multigrid level reuses one connectivity.
Conventions#
residual(…) returns with ; weak=True returns
. Solvers, adjoints and error estimates use exclusively.
Python-level structure (dimension, degree, boundary kinds, flux names) is fixed when a
Discretization is built and never appears inside traced code as data-dependent control flow.
Everything numerical — state, geometry, flow parameters, operator tables — is traced.
- A boundary condition: write a function returning
(UL, UR, Ub)and register it inBOUNDARY_CONDITIONS; add it toWALL_KINDS/ viscous masks if applicable; add it to the linearisation study’s configurations. - A functional: return a
Functionalfrom a function of(U, geom, th); build surface quantities withSurfaceOpsso they reuse the residual’s fluxes. - A mesh generator: produce a geometry lattice and call
structured_mesh; add a preset. - A pipeline stage: add a task function in
gyre.pipeline.tasksand its name toCOMPUTE_STAGES. - An agent tool: add a REST endpoint first, then a described wrapper in
gyre.agent.server.