rumoca 0.7.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rumoca-0.7.1/MANIFEST.in +3 -0
- rumoca-0.7.1/PKG-INFO +416 -0
- rumoca-0.7.1/README.md +376 -0
- rumoca-0.7.1/pyproject.toml +86 -0
- rumoca-0.7.1/rumoca/__init__.py +25 -0
- rumoca-0.7.1/rumoca/compiler.py +417 -0
- rumoca-0.7.1/rumoca/version.py +3 -0
- rumoca-0.7.1/rumoca.egg-info/PKG-INFO +416 -0
- rumoca-0.7.1/rumoca.egg-info/SOURCES.txt +12 -0
- rumoca-0.7.1/rumoca.egg-info/dependency_links.txt +1 -0
- rumoca-0.7.1/rumoca.egg-info/requires.txt +17 -0
- rumoca-0.7.1/rumoca.egg-info/top_level.txt +1 -0
- rumoca-0.7.1/setup.cfg +4 -0
- rumoca-0.7.1/tests/test_compiler.py +202 -0
rumoca-0.7.1/MANIFEST.in
ADDED
rumoca-0.7.1/PKG-INFO
ADDED
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rumoca
|
|
3
|
+
Version: 0.7.1
|
|
4
|
+
Summary: Python interface for the Rumoca Modelica compiler
|
|
5
|
+
Author: Rumoca Contributors
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/jgoppert/rumoca
|
|
8
|
+
Project-URL: Documentation, https://github.com/jgoppert/rumoca/blob/main/python/README.md
|
|
9
|
+
Project-URL: Repository, https://github.com/jgoppert/rumoca
|
|
10
|
+
Project-URL: Issues, https://github.com/jgoppert/rumoca/issues
|
|
11
|
+
Keywords: modelica,compiler,simulation,dae,code-generation
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Rust
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering
|
|
23
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
24
|
+
Classifier: Topic :: Software Development :: Compilers
|
|
25
|
+
Requires-Python: >=3.8
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
30
|
+
Requires-Dist: black>=23.0; extra == "dev"
|
|
31
|
+
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
32
|
+
Provides-Extra: cyecca
|
|
33
|
+
Requires-Dist: cyecca>=0.1.0; extra == "cyecca"
|
|
34
|
+
Provides-Extra: notebook
|
|
35
|
+
Requires-Dist: jupyter>=1.0; extra == "notebook"
|
|
36
|
+
Requires-Dist: matplotlib>=3.5; extra == "notebook"
|
|
37
|
+
Requires-Dist: numpy>=1.20; extra == "notebook"
|
|
38
|
+
Provides-Extra: all
|
|
39
|
+
Requires-Dist: rumoca[cyecca,dev,notebook]; extra == "all"
|
|
40
|
+
|
|
41
|
+
# Rumoca Python Interface
|
|
42
|
+
|
|
43
|
+
Python wrapper for the [Rumoca](https://github.com/jgoppert/rumoca) Modelica compiler, enabling seamless integration with [Cyecca](https://github.com/cognipilot/cyecca) for code generation and simulation.
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
### Prerequisites
|
|
48
|
+
|
|
49
|
+
1. **Build Rumoca** (Rust toolchain required):
|
|
50
|
+
```bash
|
|
51
|
+
cd /path/to/rumoca
|
|
52
|
+
cargo build --release
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
2. **Add to PATH** (optional but recommended):
|
|
56
|
+
```bash
|
|
57
|
+
export PATH=$PATH:/path/to/rumoca/target/release
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Install Python Package
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# From source (development)
|
|
64
|
+
cd rumoca/python
|
|
65
|
+
pip install -e .
|
|
66
|
+
|
|
67
|
+
# With Cyecca integration
|
|
68
|
+
pip install -e ".[cyecca]"
|
|
69
|
+
|
|
70
|
+
# With Jupyter notebook support
|
|
71
|
+
pip install -e ".[notebook]"
|
|
72
|
+
|
|
73
|
+
# Everything
|
|
74
|
+
pip install -e ".[all]"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Quick Start
|
|
78
|
+
|
|
79
|
+
### Basic Usage
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
import rumoca
|
|
83
|
+
|
|
84
|
+
# Compile a Modelica model
|
|
85
|
+
result = rumoca.compile("bouncing_ball.mo")
|
|
86
|
+
|
|
87
|
+
# Export to Base Modelica JSON
|
|
88
|
+
result.export_base_modelica_json("bouncing_ball.json")
|
|
89
|
+
|
|
90
|
+
# Or get as string
|
|
91
|
+
json_str = result.to_base_modelica_json()
|
|
92
|
+
|
|
93
|
+
# Or get as Python dict
|
|
94
|
+
model_dict = result.to_base_modelica_dict()
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Integration with Cyecca
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
import rumoca
|
|
101
|
+
from cyecca.io import import_base_modelica
|
|
102
|
+
|
|
103
|
+
# Compile Modelica model
|
|
104
|
+
result = rumoca.compile("my_model.mo")
|
|
105
|
+
result.export_base_modelica_json("my_model.json")
|
|
106
|
+
|
|
107
|
+
# Import into Cyecca
|
|
108
|
+
model = import_base_modelica("my_model.json")
|
|
109
|
+
|
|
110
|
+
print(f"Model: {model.name}")
|
|
111
|
+
print(f"States: {[v.name for v in model.variables if v.is_state]}")
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Code Generation with Cyecca
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
import rumoca
|
|
118
|
+
from cyecca.io.base_modelica import import_base_modelica
|
|
119
|
+
from cyecca.backends.casadi import generate_casadi
|
|
120
|
+
from cyecca.backends.sympy import generate_sympy
|
|
121
|
+
|
|
122
|
+
# Compile to Base Modelica
|
|
123
|
+
result = rumoca.compile("my_model.mo")
|
|
124
|
+
result.export_base_modelica_json("my_model.json")
|
|
125
|
+
|
|
126
|
+
# Import with Cyecca
|
|
127
|
+
model = import_base_modelica("my_model.json")
|
|
128
|
+
|
|
129
|
+
# Generate CasADi code
|
|
130
|
+
casadi_code = generate_casadi(model)
|
|
131
|
+
with open("my_model_casadi.py", "w") as f:
|
|
132
|
+
f.write(casadi_code)
|
|
133
|
+
|
|
134
|
+
# Generate SymPy code
|
|
135
|
+
sympy_code = generate_sympy(model)
|
|
136
|
+
with open("my_model_sympy.py", "w") as f:
|
|
137
|
+
f.write(sympy_code)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Jupyter Notebook Workflow
|
|
141
|
+
|
|
142
|
+
See [examples/bouncing_ball_demo.ipynb](../examples/notebooks/bouncing_ball_demo.ipynb) for a complete example.
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
# Cell 1: Compile
|
|
146
|
+
import rumoca
|
|
147
|
+
from cyecca.io import import_base_modelica
|
|
148
|
+
import matplotlib.pyplot as plt
|
|
149
|
+
|
|
150
|
+
result = rumoca.compile("bouncing_ball.mo")
|
|
151
|
+
result.export_base_modelica_json("bouncing_ball.json")
|
|
152
|
+
|
|
153
|
+
# Cell 2: Import and inspect
|
|
154
|
+
model = import_base_modelica("bouncing_ball.json")
|
|
155
|
+
print(f"States: {[v.name for v in model.variables if not v.is_parameter]}")
|
|
156
|
+
|
|
157
|
+
# Cell 3: Generate simulation code
|
|
158
|
+
from cyecca.codegen import generate_simulation_code
|
|
159
|
+
code = generate_simulation_code(model, backend="python")
|
|
160
|
+
|
|
161
|
+
# Cell 4: Simulate and plot
|
|
162
|
+
results = code.simulate(t_span=(0, 10), dt=0.01)
|
|
163
|
+
plt.plot(results['t'], results['h'], label='Height')
|
|
164
|
+
plt.plot(results['t'], results['v'], label='Velocity')
|
|
165
|
+
plt.legend()
|
|
166
|
+
plt.show()
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## API Reference
|
|
170
|
+
|
|
171
|
+
### `rumoca.compile(model_file, rumoca_bin=None)`
|
|
172
|
+
|
|
173
|
+
Compile a Modelica model file.
|
|
174
|
+
|
|
175
|
+
**Parameters:**
|
|
176
|
+
- `model_file` (str | Path): Path to the Modelica (.mo) file
|
|
177
|
+
- `rumoca_bin` (str | Path, optional): Path to rumoca binary (auto-detected if None)
|
|
178
|
+
|
|
179
|
+
**Returns:**
|
|
180
|
+
- `CompilationResult`: Object containing the compiled model
|
|
181
|
+
|
|
182
|
+
**Raises:**
|
|
183
|
+
- `FileNotFoundError`: If model file doesn't exist
|
|
184
|
+
- `RuntimeError`: If rumoca binary not found
|
|
185
|
+
- `CompilationError`: If compilation fails
|
|
186
|
+
|
|
187
|
+
**Example:**
|
|
188
|
+
```python
|
|
189
|
+
result = rumoca.compile("bouncing_ball.mo")
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### `CompilationResult`
|
|
193
|
+
|
|
194
|
+
Result of compiling a Modelica model.
|
|
195
|
+
|
|
196
|
+
#### Methods
|
|
197
|
+
|
|
198
|
+
##### `to_base_modelica_json() -> str`
|
|
199
|
+
|
|
200
|
+
Export model to Base Modelica JSON format as a string.
|
|
201
|
+
|
|
202
|
+
**Returns:**
|
|
203
|
+
- `str`: JSON string containing Base Modelica representation (MCP-0031)
|
|
204
|
+
|
|
205
|
+
**Raises:**
|
|
206
|
+
- `CompilationError`: If export fails
|
|
207
|
+
|
|
208
|
+
**Example:**
|
|
209
|
+
```python
|
|
210
|
+
result = rumoca.compile("model.mo")
|
|
211
|
+
json_str = result.to_base_modelica_json()
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
##### `export_base_modelica_json(output_file)`
|
|
215
|
+
|
|
216
|
+
Export model to Base Modelica JSON file.
|
|
217
|
+
|
|
218
|
+
**Parameters:**
|
|
219
|
+
- `output_file` (str | Path): Path where JSON file will be written
|
|
220
|
+
|
|
221
|
+
**Raises:**
|
|
222
|
+
- `CompilationError`: If export fails
|
|
223
|
+
|
|
224
|
+
**Example:**
|
|
225
|
+
```python
|
|
226
|
+
result = rumoca.compile("model.mo")
|
|
227
|
+
result.export_base_modelica_json("model.json")
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
##### `to_base_modelica_dict() -> dict`
|
|
231
|
+
|
|
232
|
+
Get Base Modelica representation as Python dictionary.
|
|
233
|
+
|
|
234
|
+
**Returns:**
|
|
235
|
+
- `dict`: Dictionary containing Base Modelica model data
|
|
236
|
+
|
|
237
|
+
**Example:**
|
|
238
|
+
```python
|
|
239
|
+
result = rumoca.compile("model.mo")
|
|
240
|
+
data = result.to_base_modelica_dict()
|
|
241
|
+
print(f"Parameters: {len(data['parameters'])}")
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
##### `export(template_file) -> str`
|
|
245
|
+
|
|
246
|
+
Advanced: Export using a custom template.
|
|
247
|
+
|
|
248
|
+
**Parameters:**
|
|
249
|
+
- `template_file` (str | Path): Path to custom Jinja2 template file
|
|
250
|
+
|
|
251
|
+
**Returns:**
|
|
252
|
+
- `str`: Generated code as string
|
|
253
|
+
|
|
254
|
+
**Note:** For standard code generation, use `to_base_modelica_json()` + Cyecca instead.
|
|
255
|
+
|
|
256
|
+
## Examples
|
|
257
|
+
|
|
258
|
+
### Example 1: Simple Compilation
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
import rumoca
|
|
262
|
+
|
|
263
|
+
# Compile and export in one go
|
|
264
|
+
result = rumoca.compile("integrator.mo")
|
|
265
|
+
result.export_base_modelica_json("integrator.json")
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Example 2: Inspect Model Structure
|
|
269
|
+
|
|
270
|
+
```python
|
|
271
|
+
import rumoca
|
|
272
|
+
|
|
273
|
+
result = rumoca.compile("rover.mo")
|
|
274
|
+
model_data = result.to_base_modelica_dict()
|
|
275
|
+
|
|
276
|
+
print(f"Model: {model_data['model_name']}")
|
|
277
|
+
print(f"Parameters: {len(model_data['parameters'])}")
|
|
278
|
+
print(f"Variables: {len(model_data['variables'])}")
|
|
279
|
+
print(f"Equations: {len(model_data['equations'])}")
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Example 3: Full Workflow with Cyecca
|
|
283
|
+
|
|
284
|
+
```python
|
|
285
|
+
import rumoca
|
|
286
|
+
from cyecca.io.base_modelica import import_base_modelica
|
|
287
|
+
from cyecca.backends.casadi import generate_casadi
|
|
288
|
+
|
|
289
|
+
# Step 1: Compile Modelica to Base Modelica
|
|
290
|
+
result = rumoca.compile("quadrotor.mo")
|
|
291
|
+
result.export_base_modelica_json("quadrotor.json")
|
|
292
|
+
|
|
293
|
+
# Step 2: Import with Cyecca
|
|
294
|
+
model = import_base_modelica("quadrotor.json")
|
|
295
|
+
|
|
296
|
+
# Step 3: Generate CasADi code
|
|
297
|
+
casadi_code = generate_casadi(model)
|
|
298
|
+
|
|
299
|
+
# Step 4: Save generated code
|
|
300
|
+
with open("quadrotor_casadi.py", "w") as f:
|
|
301
|
+
f.write(casadi_code)
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Example 4: Error Handling
|
|
305
|
+
|
|
306
|
+
```python
|
|
307
|
+
import rumoca
|
|
308
|
+
|
|
309
|
+
try:
|
|
310
|
+
result = rumoca.compile("my_model.mo")
|
|
311
|
+
result.export_base_modelica_json("output.json")
|
|
312
|
+
except FileNotFoundError as e:
|
|
313
|
+
print(f"Model file not found: {e}")
|
|
314
|
+
except rumoca.CompilationError as e:
|
|
315
|
+
print(f"Compilation failed: {e}")
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Architecture
|
|
319
|
+
|
|
320
|
+
### Subprocess-Based Wrapper
|
|
321
|
+
|
|
322
|
+
The current implementation uses a subprocess-based wrapper that:
|
|
323
|
+
|
|
324
|
+
1. Calls the `rumoca` binary as a subprocess with `--json` flag
|
|
325
|
+
2. Receives Base Modelica JSON via stdout
|
|
326
|
+
3. Parses JSON into Python dictionaries
|
|
327
|
+
4. Captures stderr for error reporting
|
|
328
|
+
|
|
329
|
+
**Advantages:**
|
|
330
|
+
- Simple implementation
|
|
331
|
+
- Easy to maintain
|
|
332
|
+
- Works with existing Rumoca binary
|
|
333
|
+
- Fast native JSON serialization in Rust
|
|
334
|
+
|
|
335
|
+
**Workflow:**
|
|
336
|
+
```
|
|
337
|
+
Python → subprocess(rumoca --json) → Base Modelica JSON → Python dict
|
|
338
|
+
↓
|
|
339
|
+
Cyecca
|
|
340
|
+
↓
|
|
341
|
+
Generated Code
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Future: PyO3 Bindings
|
|
345
|
+
|
|
346
|
+
A future version may use [PyO3](https://pyo3.rs/) for native Rust-Python bindings:
|
|
347
|
+
|
|
348
|
+
- Direct access to Rumoca's DAE structures
|
|
349
|
+
- No subprocess overhead
|
|
350
|
+
- Zero-copy data transfer
|
|
351
|
+
- Tighter integration possibilities
|
|
352
|
+
|
|
353
|
+
## Troubleshooting
|
|
354
|
+
|
|
355
|
+
### "Rumoca binary not found"
|
|
356
|
+
|
|
357
|
+
**Solution 1:** Add rumoca to PATH:
|
|
358
|
+
```bash
|
|
359
|
+
export PATH=$PATH:/path/to/rumoca/target/release
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**Solution 2:** Specify binary path explicitly:
|
|
363
|
+
```python
|
|
364
|
+
result = rumoca.compile("model.mo", rumoca_bin="/path/to/rumoca")
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Compilation errors
|
|
368
|
+
|
|
369
|
+
Check the Modelica syntax by running rumoca directly:
|
|
370
|
+
```bash
|
|
371
|
+
rumoca your_model.mo --json
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
If successful, you should see Base Modelica JSON output.
|
|
375
|
+
|
|
376
|
+
## Development
|
|
377
|
+
|
|
378
|
+
### Running Tests
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
cd rumoca/python
|
|
382
|
+
pip install -e ".[dev]"
|
|
383
|
+
pytest
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### Type Checking
|
|
387
|
+
|
|
388
|
+
```bash
|
|
389
|
+
mypy rumoca
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Code Formatting
|
|
393
|
+
|
|
394
|
+
```bash
|
|
395
|
+
black rumoca tests
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
## Contributing
|
|
399
|
+
|
|
400
|
+
Contributions welcome! Please:
|
|
401
|
+
|
|
402
|
+
1. Run tests: `pytest`
|
|
403
|
+
2. Check types: `mypy rumoca`
|
|
404
|
+
3. Format code: `black rumoca tests`
|
|
405
|
+
4. Update documentation
|
|
406
|
+
|
|
407
|
+
## License
|
|
408
|
+
|
|
409
|
+
Apache 2.0 (same as Rumoca)
|
|
410
|
+
|
|
411
|
+
## See Also
|
|
412
|
+
|
|
413
|
+
- [Rumoca Compiler](https://github.com/jgoppert/rumoca)
|
|
414
|
+
- [Cyecca Code Generator](https://github.com/cognipilot/cyecca)
|
|
415
|
+
- [Base Modelica Specification (MCP-0031)](https://modelica.org/mcp/)
|
|
416
|
+
- [Modelica Language](https://www.modelica.org/)
|