Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The Four IRs

Each IR is a serializable data structure crate (rumoca-ir-*) with a schema version. This chapter says what each one is for; the binding contracts live in SPEC_0007.

AST (rumoca-ir-ast)

The parser’s output: concrete syntax with comments and spans. It represents text, not semantics — no name resolution, no types. Formatters, pretty-printers, and doc generators work here because they need the original syntax. Every node carries a Span, and that provenance must survive any AST merging.

Dump it as JSON: rumoca compile Model.mo --emit ast-json. The dump is the parser’s tree of that one file, taken before any source root is loaded or any name is resolved. Rumoca does not reconstruct Modelica from the tree because doing so would lose source syntax; use the formatter for source-preserving output.

Flat (rumoca-ir-flat)

The instantiated, modified, flattened model: variables and equations with fully qualified names, no unresolved references, no pending modification chains. Two things are deliberately not done yet:

  • Arrays stay symbolic. Scalarization happens later, with shape metadata, only for backends that need it.
  • Modelica operators survive. der(), pre(), sample(), initial() are still expression nodes; their semantic lowering is the DAE phase’s job.

Flat is the right level for flat-Modelica export and for structural transformations that preserve Modelica expression form.

Dump it: --emit flat-mo / flat-json.

DAE (rumoca-ir-dae)

The stable contract of the whole project: the MLS Appendix B canonical DAE. Pure functions over the variable vector v := [p; t; ẋ; x; y; z; m; pre(z); pre(m)], partitioned by kind:

IDFunctionRole
B.1afx(v, c) = 0Continuous DAE residual
B.1bfz(v, c) = 0Discrete real update
B.1cfm(v, c) = 0Discrete-valued update
B.1dfc(relation(v))Event conditions

By the time a model is DAE, no source temporal operator survives — not in any partition. pre has become explicit __pre__.* parameter slots; reinit has become guarded update equations; sample has become event and clock metadata; assert/terminate have become event actions. A validation pass (appendix_b_validation) enforces this positively rather than relying on downstream code to cope.

The DAE is also deliberately lean: it represents Modelica semantics and source identity, never solver work products. If you are tempted to cache a Jacobian, a BLT ordering, or a scalarized variant inside the DAE — that belongs in structural analysis results or Solve artifacts.

Dump it: --emit dae-mo / dae-json. The dae-mo form is what the Show DAE buttons in both guides render.

Solve (rumoca-ir-solve)

A register-machine representation of the DAE functions: ComputeBlock graphs mixing ScalarProgramBlocks (flat register programs, one scalar output each) with tensor program nodes (MatMul, LinSolve, …) that carry explicit shape/layout metadata and a fallible scalar fallback. Solve adds no new mathematics — it changes format so execution backends (interpreter, Cranelift JIT, MLIR, CUDA, generated C/Rust) can consume the system directly, choosing scalar expansion or native tensor kernels.

Dump it: --emit solve-json (there is no Modelica rendering of Solve).

Schema Versions

Serialized DAE and Solve payloads carry a mandatory root schema_version; deserializers reject unsupported versions. The policy is in IR Schema Versioning.