Architecture

The package is a pipeline. Generated ANTLR parsers turn SysML v2 text into parse trees, and the builder turns parse trees into a typed object model. Everything else consumes that model: the exporters, the validator, the interpreter, the diagrams, and the analysis bridges.

Package layout

grammars/                  SysML.g4 + KerML.g4 (upstream + local patches)
scripts/generate_parsers.py  regenerate src/longeron/_gen from the grammars
scripts/check_corpus.py    reproduce the corpus badge: sweep SysML-v2-Release
src/longeron/
    _gen/                  generated ANTLR lexers/parsers (committed)
    parser.py              text -> parse tree, error collection
    builder.py             parse tree -> model (the SysML front-end)
    model.py               model element dataclasses (Literal-typed vocabularies)
    ast.py                 expression AST + precedence-aware printer
    export.py              model -> JSON / SysML text, save(), workspace save
    importer.py            JSON -> model (lossless round-trip)
    workspace.py           multi-file loading + content-addressed model cache
    kerml.py               model -> KerML projection
    interpreter.py         evaluation, instantiation, actions, states, snapshot
    m0.py                  M0 interpretations: populations of individuals
    validation.py          longeron lint / validate(), incl. the dimensional lint
    units.py               derived unit table + optional pint conversion facade
    edit.py                validated edits: values, renames, docs
    stdlib.py + _stdlib/   vendored OMG standard library (+ prebuilt JSON)
    ecore.py + _spec/      projection onto the OMG spec metamodel (pyecore)
    api.py                 OMG Systems Modeling API JSON interchange
    server.py / client.py  Systems Modeling API server (longeron serve) + client
    rdf.py                 RDF projection + SPARQL convenience (rdflib)
    rag.py                 LLM retrieval substrate: chunks, neighborhoods, search
    diagrams.py            interactive ELK diagrams (ipyelk)
    render.py + _js/       headless SVG/PNG export (vendored elkjs via node)
    replay.py              simulation replay over the diagrams
    explorer.py            the model explorer + its tree engine
    app.py + inspector.py  the review workbench + the property sheet
    toolbar.py + views.py  diagram tools + saved views
    widgets/               the widget catalog (one import) + graph3d
    analysis/              scoreboard, trades, mdao, verify, smt, geometry,
                           3D viewers, mission globe, dashboards, grand tour
    errors.py              one error family (SysMLError, MissingExtraError)
    cli.py                 the `longeron` console command
vendor/ipyelk/             vendored ipyelk 2.1.1 + local fixes (editable)
npm/                       the JupyterLab launcher tile (prebuilt; ships in the wheel)
examples/                  the DeepScout program (deepscout/) + analysis
                           conventions + kernel.kerml + demo.py
tests/                     pytest suite (see the coverage badge above)
.github/workflows/ci.yml   pixi-based: check + test matrix (3.10-3.13)
                           + grammar-regen drift check (antlr/JDK from lock)
Makefile                   make check = ruff + mypy + pytest (venv/pip route)

How a model flows through the package

  1. parser.py runs the generated ANTLR parser and collects syntax errors.

  2. builder.py walks the parse tree and produces model.py dataclasses. Expressions become compact AST nodes (ast.py), not parse-tree references.

  3. export.py renders the model to JSON or textual notation; importer.py reads the JSON back; kerml.py projects onto KerML.

  4. interpreter.py resolves qualified names (imports, aliases, specialization) and executes the model; snapshot converts runtime instances back into model elements.

Execution semantics (and their limits)

This is a modeling sandbox, not a full KerML semantic engine. What executes:

  • Actions: bodies without successions run in declaration order. Bodies with explicit successions (first start then a; first a then b;) run as a control-flow graph: unreachable steps do not execute, decide nodes choose the first satisfied guard (with else fallback), guarded loops back-edge, and fork/join branches run sequentially in declaration order (no interleaving). accept after d / accept at t advance the action’s clock (ActionResult.time); accept when c raises on a false condition (a would-be deadlock).

  • State machines are hierarchical: composite states enter through their own entry; then S; transition, inner states get the first chance to consume an event, and exits cascade innermost-first. parallel states activate all child regions concurrently (SimulationResult.active_states). Time triggers (accept after/accept at) fire when a plain number in the event list advances the simulation clock; accept when c transitions fire as soon as their condition holds.

  • Quantities evaluate to their magnitude: 10 [SI::m] evaluates to 10.

  • Standard library: a curated subset of the official model library ships with the package (all 21 Systems Library files + core Quantities/Units + a KerML-kernel shim; see longeron/_stdlib/README.md). Opt in with longeron.add_standard_library(model) or --stdlib on the CLI: library types resolve (Parts::Part, ISQ::mass, SI::kg), public import re-exports and aliases follow, and istype checks work against library definitions. A bundled prebuilt JSON snapshot makes loading instant; the KerML Kernel Libraries themselves are not loaded (KerML is parse-only), so inherited library defaults that need unimplemented kernel functions degrade to None instead of failing. The prebuilt ships as plain JSON (_stdlib/prebuilt.json) — inspectable text, no pickles anywhere.

  • Multiplicity expansion: exact bounds ([4]) expand fully; ranges populate their lower bound ([0..*] gives an empty list), which keeps the library’s self-referential compositions finite.

The analysis stack

longeron.analysis projects executable models onto external solvers. Each submodule imports its solver lazily, so the package itself adds no third-party dependencies:

  • longeron.analysis.mdao — part trees and calcs become OpenMDAO Problems: derived attributes turn into components, free attributes into design variables, and constraints into margin outputs. @ExternalAnalysis annotations swap higher-fidelity components in for calc bodies.

  • longeron.analysis.trades — variation/variant catalogs become OR-Tools CP-SAT models for discrete architecture trade studies, scored exactly through the interpreter.

  • longeron.analysis.smt — requirement sets become Z3 assertions: consistency checks, conflict cores, and design-space bounds over the reals.

  • longeron.analysis.viz, longeron.analysis.structure, longeron.analysis.dashboard — figures, N2/network views of the generated problems, and the linked mission-compromise dashboard.

  • longeron.analysis.geometry / longeron.widgets.viewer3d — parametric to-scale meshes for architecture mixes (stdlib-only math) and a small three.js viewer. Real CAD solids (STEP export) live behind the cad extra.

The guide Choosing an analysis matches questions to bridges, and tutorials 4 and 6 drive the whole stack end to end.

Vendored ipyelk

The interactive diagrams (longeron.diagrams) are built on ipyelk, which is vendored under vendor/ipyelk (BSD-3-Clause, tag v2.1.1) and installed editable so it can be patched as needed: headless-safe scheduling, resend-with-backoff browser round-trips, error channels, and a prebuilt JupyterLab extension rebuilt from the patched TypeScript sources. Every local patch is marked LOCAL PATCH and catalogued in vendor/ipyelk/README.vendor.md; the history is tracked by git log -- vendor/ipyelk.

Layout normally runs in the browser (elkjs). For tests, exports, and this documentation build, longeron.render runs the same elkjs (vendored as longeron/_js/elk.bundled.js, EPL-2.0) in a node subprocess and draws styled SVG/PNG headlessly.

Grammar patches

The grammars carry ten local patches against their upstream source, and one known precedence deviation from the OMG specification remains. The guide Grammar conformance carries the patch table, the corpus result, and the deviation. The full per-patch rationale lives in the README.

Design documents

Deeper design rationale for major subsystems: