Rumoca
A modern Modelica compiler written in Rust that parses Modelica and exports a Base Modelica IR (MCP-0031). This IR is consumed by Cyecca for simulation and code generation with CasADi, SymPy, JAX, and other backends.
Design Philosophy
Rumoca parses Modelica source files and exports a Base Modelica IR - the equation-based, causal subset designed for interchange between tools:
- Input: Modelica source files (
.mo) - currently parses standard Modelica, with planned support for direct Base Modelica parsing - Output: Base Modelica IR (JSON) - a structured intermediate representation suitable for analysis and code generation
- Consumer: Cyecca - provides symbolic manipulation, simulation, and multi-backend code generation
This separation of concerns allows Rumoca to focus on fast, reliable parsing while Cyecca handles the symbolic analysis and backend-specific code generation.
Features
- 🚀 Fast: Written in Rust with efficient parsing using PAROL
- 🎯 Type-safe: Strongly-typed AST with compile-time guarantees
- ✅ Standards-compliant: Exports to Base Modelica IR (MCP-0031)
- 🔒 Reliable: Native serde_json serialization, not template-based
- 📚 Well-tested: Comprehensive test suite with 87 automated tests
- 🛠️ Developer-friendly: Clean API for library usage
- 🔄 Cross-platform: Works on Linux, macOS, and Windows
Quick Start
Installation
Install via Cargo (requires Rust):
Verify installation:
Basic Usage
Command Line
Export to Base Modelica JSON (recommended):
Use with Cyecca for code generation:
# Export to Base Modelica
# Generate CasADi code with Cyecca
Enable verbose output:
Library Usage
Add to your Cargo.toml:
[]
= "0.7"
Use in your code:
use Compiler;
See examples/ for more complete examples.
Python Usage
The python/ directory contains a Python wrapper that calls the rumoca CLI:
# Compile a Modelica file
=
# Export to Base Modelica JSON
=
# Or get as dict
=
See python/README.md for full documentation.
Multi-File Compilation
When your model depends on libraries in separate files:
use Compiler;
Package Directory Compilation
Compile Modelica Standard Library-style package directories with package.mo and package.order:
use Compiler;
Example Workflow
Step 1: Write Modelica Model
model Integrator
Real x(start=0.0);
equation
der(x) = 1.0;
end Integrator;
Step 2: Export to Base Modelica JSON
Step 3: Generate Code with Cyecca
# Import Base Modelica IR
=
# Generate CasADi code
=
Why this approach?
- ⚡ Fast: Native JSON serialization in Rust
- 🔒 Type-safe: Compile-time validation
- ✅ Standard: MCP-0031 compliant Base Modelica IR
- 🔧 Flexible: Use any Cyecca backend (CasADi, SymPy, JAX, etc.)
Modelica 3.7 Specification Compliance
Rumoca targets the Modelica Language Specification 3.7-dev. This section documents compliance status, deviations, and known limitations.
Fully Supported (Spec Chapters 2-8, 11-12)
| Feature | Spec Reference | Notes |
|---|---|---|
| Class definitions | Ch. 4 | model, class, block, connector, record, type, package, function |
| Components | Ch. 4.4 | Declarations with modifications, array subscripts |
| Inheritance | Ch. 7.1 | extends clause with recursive resolution |
| Equations | Ch. 8 | Simple, connect, if, for, when equations |
| Algorithms | Ch. 11 | Assignment, if, for, while, when statements |
| Expressions | Ch. 3 | Binary/unary ops, function calls, if-expressions, arrays |
| Type prefixes | Ch. 4.4 | flow, stream, discrete, parameter, constant, input, output |
| Built-in operators | Ch. 3.7 | der(), pre(), reinit(), time |
| Modifications | Ch. 7.2 | Component modifications, class modifications |
| Flattening | Ch. 5.6 | Full hierarchical expansion with proper scoping |
Partially Supported
| Feature | Spec Reference | Status | Limitation |
|---|---|---|---|
| Connect equations | Ch. 9.1 | ✅ Basic | Flow/potential semantics implemented; stream not supported |
| Arrays | Ch. 10 | ✅ Good | Dimensions tracked and exported; array functions supported; literals with {} supported |
| Functions | Ch. 12 | ✅ Good | Single and multi-output functions inlined; tuple equations (a,b) = func() supported |
| Packages | Ch. 13 | ✅ Good | Nested packages; cross-package function calls; path-based model lookup; package.mo/package.order directory structure (Spec 13.4); MODELICAPATH (Spec 13.3) |
| Imports | Ch. 13.2 | ✅ Good | All import styles: qualified, renamed, unqualified (.*), selective ({a,b}) |
| Annotations | Ch. 18 | ⚠️ Parsed | Recognized but ignored during processing |
| External functions | Ch. 12.9 | ⚠️ Parsed | external keyword recognized; no linking |
Not Implemented
| Feature | Spec Reference | Notes |
|---|---|---|
| Overloaded operators | Ch. 14 | operator class prefix recognized only |
| State machines | Ch. 17 | Synchronous language elements |
| Balanced models | Ch. 4.8 | ✅ Equation/variable counting with warnings |
| Overconstrained connectors | Ch. 9.4 | Connections.root, branch, etc. |
| Expandable connectors | Ch. 9.1.3 | Dynamic connector sizing |
| Inner/outer | Ch. 5.4 | Keywords recognized; lookup not implemented |
| Redeclarations | Ch. 7.3 | redeclare, replaceable parsed only |
Known Deviations from Spec
- Flattening is mandatory (Spec 5.6): All models are fully flattened; no support for preserving hierarchy
- Connect semantics simplified (Spec 9.1): Uses union-find for connection sets;
streamvariables not handled - Balanced model checking (Spec 4.8): Reports warnings for over/under-determined models; does not prevent compilation
- Limited type checking: Nominal type system not enforced; structural compatibility assumed
- Event semantics (Spec 8.5):
noEvent,smooth,sample,edge,change,initial,terminalare supported - Array size inference: Explicit sizes required; no automatic inference from context
Built-in Functions
| Function | Status | Notes |
|---|---|---|
der(x) |
✅ | State derivative |
pre(x) |
✅ | Previous discrete value |
reinit(x, expr) |
✅ | In when clauses only |
time |
✅ | Global simulation time |
sin, cos, tan |
✅ | Basic trig |
asin, acos, atan, atan2 |
✅ | Inverse trig |
sinh, cosh, tanh |
✅ | Hyperbolic trig |
exp, log, log10 |
✅ | Exponential/logarithmic |
sqrt |
✅ | Square root |
abs, sign |
✅ | Absolute value/sign |
floor, ceil |
✅ | Rounding |
mod, rem, div, integer |
✅ | Integer operations |
min, max |
✅ | Scalar min/max |
sum, product |
✅ | Array reductions |
zeros, ones, fill, identity |
✅ | Array construction |
size, ndims |
✅ | Array information |
transpose, symmetric, cross, skew |
✅ | Array transformations |
outerProduct, diagonal, linspace |
✅ | Advanced array ops |
scalar, vector, matrix |
✅ | Type conversion |
noEvent |
✅ | Suppress event generation |
smooth |
✅ | Smoothness assertion |
sample, edge, change |
✅ | Discrete event detection |
initial, terminal |
✅ | Simulation phase |
Code Generation Backends
Rumoca exports to Base Modelica JSON. Use Cyecca to generate code for various frameworks:
- CasADi (Python) - Automatic differentiation, optimal control
- SymPy (Python) - Symbolic computation
- JAX (Python) - Machine learning, autodiff
- NumPy (Python) - Numerical computation
- More backends - Cyecca is extensible!
Architecture
Rumoca processes Modelica files and exports to Base Modelica IR:
Modelica Source → Parse → Flatten → DAE → Base Modelica JSON
(AST) (Flat) (DAE) (MCP-0031)
↓
Cyecca
↓
CasADi/SymPy/JAX/etc.
- Parse: Converts Modelica text to Abstract Syntax Tree (AST)
- Flatten: Expands hierarchical models into flat structure
- DAE: Classifies variables and equations for DAE representation
- Export: Serializes to Base Modelica JSON (MCP-0031 standard)
- Code Generation: Use Cyecca to generate backend-specific code
Development
Building from Source
Running Tests
Running Examples
Code Quality Checks
Advanced: Custom Templates
For advanced users, Rumoca supports custom template-based export for specialized use cases (e.g., non-standard formats, embedded systems):
Rumoca uses MiniJinja for template rendering. The DAE structure is passed to templates as the dae variable.
Example template:
{%- for (name, component) in dae.x %}
{{ name }}: {{ component.type_name }}
{%- endfor %}
See templates/examples/ for template examples.
Note: For standard code generation (CasADi, SymPy, JAX), use the Base Modelica JSON + Cyecca workflow instead of templates.
Why Rumoca?
Motivation
There are many excellent tools for hybrid systems analysis, but porting models between different environments is challenging. Rumoca + Cyecca bridges this gap by:
- Input: Accepting Modelica, a standardized language for cyber-physical systems
- Intermediate: Base Modelica JSON (MCP-0031 standard)
- Output: Code for various frameworks via Cyecca (CasADi, SymPy, JAX, etc.)
Why Rust?
Rumoca is written in Rust for several key advantages:
- Performance: Faster parsing and processing than Python-based tools
- Safety: Memory safety without garbage collection
- Type Safety: Catch errors at compile time, not runtime
- Modern Tooling: Excellent package management, testing, and documentation
- Cross-platform: Easy deployment on Linux, macOS, and Windows
Comparison with Other Tools
| Feature | Rumoca | PyMoca | OpenModelica | Marco |
|---|---|---|---|---|
| Language | Rust | Python | Modelica/C++ | C++ |
| Parsing | PAROL | ANTLR | ANTLR | LLVM |
| Speed | Fast | Moderate | Fast | Very Fast |
| Memory Safety | ✅ | ✅ | ❌ | ❌ |
| Type Safety | ✅ | Partial | ✅ | ✅ |
| Customizable Output | ✅ | ✅ | ❌ | ❌ |
| License | Apache | BSD | OSMC-PL | GPL |
Roadmap
The following features are planned for future releases:
Short-term:
streamconnector variables andinStream/actualStreamoperators (Spec Ch. 15)- Better error messages with source locations
Medium-term:
- Inner/outer lookup (Spec 5.4)
- Redeclarations and replaceable (Spec 7.3)
- Direct Base Modelica (MCP-0031) parsing
- Expandable connectors (Spec 9.1.3)
Long-term:
- Modelica Standard Library subset support
- Synchronous language elements (Spec Ch. 16) - Clock, clocked equations, sample/hold operators
- State machines (Spec Ch. 17) - transition, initialState, activeState
- Overconstrained connection graphs (Spec 9.4) - Connections.branch, root, potentialRoot
- External function linking (Spec 12.9)
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
Key areas where help is needed:
- Additional Modelica language features
- Documentation improvements
- Bug reports and fixes
- Integration with Cyecca backends
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Dependencies
- PAROL - Parser generator and lexer
- MiniJinja - Jinja2 template engine
- Serde - Serialization framework
- Clap - Command-line argument parser
Citation
If you use Rumoca in academic work, please cite:
See Also
- Cyecca - Code generation from Base Modelica IR (currently ir branch)
- Base Modelica Specification (MCP-0031)
- Modelica Language
Acknowledgments
- Inspired by PyMoca
- Built with the excellent Rust ecosystem
- Thanks to all contributors and the Modelica community