Skip to content

Commit 4f6febc

Browse files
committed
Refactor code structure for improved readability and maintainability
fixes #14
1 parent 60eb5c9 commit 4f6febc

File tree

18 files changed

+4394
-343
lines changed

18 files changed

+4394
-343
lines changed

README.md

Lines changed: 244 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,45 @@
11
# Feel++ mo2fmu converter
22

3-
Modelica to FMU converter based on dymola
3+
Modelica to FMU converter with Dymola and OpenModelica support.
4+
5+
## Features
6+
7+
- **Multiple backends**: Supports both Dymola and OpenModelica compilers
8+
- **Automatic backend selection**: Automatically detects available compilers
9+
- **FMI 1.0, 2.0, and 3.0 support**: Generate Co-Simulation and Model Exchange FMUs
10+
- **Python API**: Programmatic access for integration into workflows
11+
- **Command-line interface**: Simple CLI with `compile` and `check` subcommands
412

513
## Installation
614

715
### From PyPI (Recommended)
816

9-
Install the latest stable release from PyPI:
17+
Install the latest stable release from PyPI using [uv](https://docs.astral.sh/uv/):
1018

1119
```console
12-
pip install feelpp-mo2fmu
20+
uv pip install feelpp-mo2fmu
1321
```
1422

15-
Or using uv (faster):
23+
### With OpenModelica Support
24+
25+
To use OpenModelica as a backend, install with the optional dependency:
1626

1727
```console
18-
uv pip install feelpp-mo2fmu
28+
uv pip install "feelpp-mo2fmu[openmodelica]"
29+
```
30+
31+
This will install [OMPython](https://github.com/OpenModelica/OMPython) for Python integration with OpenModelica.
32+
33+
### With Simulation Support
34+
35+
To run simulations and validate FMUs (useful for testing):
36+
37+
```console
38+
uv pip install "feelpp-mo2fmu[simulation]"
1939
```
2040

41+
This will install [FMPy](https://github.com/CATIA-Systems/FMPy) for FMU simulation and validation.
42+
2143
### From Source
2244

2345
For development or to use the latest unreleased features:
@@ -42,44 +64,204 @@ export DYMOLA_EXECUTABLE=/usr/local/bin/dymola
4264
export DYMOLA_WHL=Modelica/Library/python_interface/dymola-2025.1-py3-none-any.whl
4365
```
4466

45-
These environment variables are used by:
46-
- Tests (avoiding hardcoded paths)
47-
- CI/CD workflows
48-
- Command-line interface defaults
49-
5067
**Environment Variables:**
5168
- `DYMOLA_ROOT`: Path to Dymola installation root directory (default: `/opt/dymola-2025xRefresh1-x86_64/`)
5269
- `DYMOLA_EXECUTABLE`: Path to Dymola executable binary (default: `/usr/local/bin/dymola`)
5370
- `DYMOLA_WHL`: Relative path to Dymola Python wheel from DYMOLA_ROOT (default: `Modelica/Library/python_interface/dymola-2025.1-py3-none-any.whl`)
5471

55-
## Usage in command line
72+
### OpenModelica Location
73+
74+
OpenModelica can be configured via environment variables:
75+
76+
```bash
77+
export OPENMODELICA_HOME=/usr/lib/omc
78+
```
79+
80+
**Environment Variables:**
81+
- `OPENMODELICA_HOME`: Path to OpenModelica installation (default: auto-detected)
82+
83+
## Command Line Interface
84+
85+
The mo2fmu CLI provides two subcommands: `compile` and `check`.
86+
87+
### Main Help
5688

5789
```console
5890
$ mo2fmu --help
59-
Usage: mo2fmu [OPTIONS] MO OUTDIR
91+
Usage: mo2fmu [OPTIONS] COMMAND [ARGS]...
92+
93+
mo2fmu - Convert Modelica models to Functional Mock-up Units (FMUs).
94+
95+
Use 'mo2fmu compile' to generate FMUs or 'mo2fmu check' to verify compilers.
96+
97+
Options:
98+
-v, --version Show version information.
99+
--help Show this message and exit.
100+
101+
Commands:
102+
check Check availability of Modelica compilers and their FMI support.
103+
compile Compile a Modelica model to FMU.
104+
```
105+
106+
### Compile Command
107+
108+
Generate FMUs from Modelica models:
109+
110+
```console
111+
$ mo2fmu compile --help
112+
Usage: mo2fmu compile [OPTIONS] MO OUTDIR
113+
114+
Compile a Modelica model to FMU.
115+
116+
Options:
117+
--name TEXT Custom name for the FMU (default: .mo file stem).
118+
-l, --load TEXT Load one or more Modelica packages.
119+
--flags TEXT Compiler-specific flags for FMU translation.
120+
-t, --type [all|cs|me|csSolver] FMI type: cs (Co-Simulation), me (Model Exchange),
121+
all, or csSolver.
122+
--fmi-version [1|2|3] FMI version. FMI 3.0 requires Dymola 2024+
123+
or OpenModelica 1.21+.
124+
-b, --backend [dymola|openmodelica|auto]
125+
Modelica compiler backend (default: auto-detect).
126+
--dymola PATH Path to Dymola root directory.
127+
--dymola-exec PATH Path to Dymola executable.
128+
--dymola-whl PATH Path to Dymola wheel file (relative to Dymola root).
129+
-v, --verbose Enable verbose output.
130+
-f, --force Overwrite existing FMU.
131+
--help Show this message and exit.
132+
```
133+
134+
**Compile Examples:**
135+
136+
```console
137+
# Basic compilation (auto-detect backend)
138+
mo2fmu compile model.mo ./output
139+
140+
# Compile with OpenModelica backend
141+
mo2fmu compile --backend openmodelica model.mo ./output
142+
143+
# Compile FMI 3.0 Co-Simulation FMU with verbose output
144+
mo2fmu compile -v --fmi-version 3 --type cs model.mo ./output
145+
146+
# Force overwrite existing FMU
147+
mo2fmu compile -f model.mo ./output
148+
149+
# Load additional Modelica packages
150+
mo2fmu compile --load package1.mo --load package2.mo model.mo ./output
151+
```
152+
153+
### Check Command
154+
155+
Verify compiler availability and FMI support:
156+
157+
```console
158+
$ mo2fmu check --help
159+
Usage: mo2fmu check [OPTIONS]
160+
161+
Check availability of Modelica compilers and their FMI support.
60162

61163
Options:
62-
--fmumodelname TEXT change the model name of the FMU (default: .mo
63-
file stem)
64-
--load TEXT load one or more Modelica packages.
65-
--flags TEXT one or more Dymola flags for FMU translation.
66-
--type [all|cs|me|csSolver] the FMI type: cs, me, all, or csSolver.
67-
--version TEXT the FMI version.
68-
--dymola PATH path to Dymola root.
69-
--dymolapath PATH path to Dymola executable.
70-
--dymolawhl PATH path to Dymola whl file, relative to Dymola
71-
root.
72-
-v, --verbose verbose mode.
73-
-f, --force force FMU generation even if file exists.
74-
--help Show this message and exit.----
164+
--dymola PATH Path to Dymola root directory.
165+
--dymola-exec PATH Path to Dymola executable.
166+
--dymola-whl PATH Path to Dymola wheel file (relative to Dymola root).
167+
--json Output results as JSON.
168+
--help Show this message and exit.
75169
```
76170

77-
## Usage in Python
171+
**Check Examples:**
78172

79-
Here is an example of how to use the `mo2fmu` function in Python that would convert a Modelica file to an FMU:
173+
```console
174+
# Check all available compilers
175+
mo2fmu check
176+
177+
# Output as JSON (for scripting)
178+
mo2fmu check --json
179+
180+
# Check with custom Dymola path
181+
mo2fmu check --dymola /opt/dymola-2024x
182+
```
183+
184+
## Python API
185+
186+
### Recommended API
187+
188+
The recommended API provides a clean interface with automatic backend selection:
189+
190+
```python
191+
from feelpp.mo2fmu import compileFmu, getCompiler, checkCompilers
192+
193+
# Auto-detect and use available compiler
194+
result = compileFmu("path/to/model.mo", "./output")
195+
if result.success:
196+
print(f"FMU created at {result.fmu_path}")
197+
else:
198+
print(f"Error: {result.error_message}")
199+
200+
# Explicitly use OpenModelica
201+
result = compileFmu("path/to/model.mo", "./output", backend="openmodelica")
202+
203+
# Compile FMI 3.0 Model Exchange FMU
204+
result = compileFmu(
205+
"path/to/model.mo",
206+
"./output",
207+
fmiType="me",
208+
fmiVersion="3",
209+
verbose=True,
210+
)
211+
212+
# Check available compilers
213+
available = checkCompilers()
214+
for name, info in available.items():
215+
print(f"{name}: available={info['available']}, versions={info.get('fmi_versions', [])}")
216+
217+
# Get a specific compiler instance for more control
218+
compiler = getCompiler("openmodelica")
219+
if compiler.is_available:
220+
print(f"Using {compiler.name}")
221+
```
222+
223+
### Using Compiler Classes Directly
224+
225+
For full control, use the compiler classes directly:
226+
227+
```python
228+
from feelpp.mo2fmu import (
229+
DymolaCompiler,
230+
OpenModelicaCompiler,
231+
ModelicaModel,
232+
CompilationConfig,
233+
)
234+
from pathlib import Path
235+
236+
# Using OpenModelica
237+
compiler = OpenModelicaCompiler()
238+
if compiler.is_available:
239+
model = ModelicaModel(Path("path/to/model.mo"))
240+
config = CompilationConfig(
241+
fmi_type="cs", # Co-Simulation
242+
fmi_version="3", # FMI 3.0
243+
verbose=True,
244+
)
245+
result = compiler.compile(model, Path("./output"), config)
246+
247+
if result.success:
248+
print(f"FMU created: {result.fmu_path}")
249+
else:
250+
print(f"Compilation failed: {result.error_message}")
251+
252+
# Using Dymola
253+
compiler = DymolaCompiler()
254+
if compiler.is_available:
255+
result = compiler.compile(model, Path("./output"), config)
256+
```
257+
258+
### Legacy API
259+
260+
The original API is still available for backward compatibility:
80261

81262
```python
82263
from feelpp.mo2fmu import mo2fmu
264+
83265
mo2fmu(
84266
mo_file="path/to/model.mo",
85267
outdir="path/to/output/dir",
@@ -92,10 +274,44 @@ mo2fmu(
92274
dymola_executable="/path/to/dymola/executable",
93275
dymola_whl="/path/to/dymola.whl",
94276
verbose=True,
95-
force=False
277+
force=False,
278+
backend="dymola", # or "openmodelica", "auto"
96279
)
97280
```
98281

282+
## Backend Comparison
283+
284+
| Feature | Dymola | OpenModelica |
285+
|---------|--------|--------------|
286+
| License | Commercial | Open Source (GPL) |
287+
| FMI 1.0 |||
288+
| FMI 2.0 |||
289+
| FMI 3.0 | ✓ (2024+) | ✓ (v1.21+) |
290+
| Co-Simulation |||
291+
| Model Exchange |||
292+
| csSolver type |||
293+
| Modelica Standard Library |||
294+
| BuildingSystems || Partial |
295+
| Buildings Library |||
296+
297+
## Running Tests
298+
299+
The test suite includes unit tests and FMU simulation tests:
300+
301+
```console
302+
# Run all tests
303+
uv run pytest
304+
305+
# Run with verbose output
306+
uv run pytest -v
307+
308+
# Run only unit tests (no simulation)
309+
uv run pytest tests/test_compilers.py tests/test_mo2fmu.py
310+
311+
# Run simulation tests (requires FMPy)
312+
uv run pytest tests/test_fmu_simulation.py
313+
```
314+
99315
## Continuous Integration
100316

101317
Our GitHub Actions workflow (`.github/workflows/ci.yml`) includes:

pyproject.toml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "feelpp-mo2fmu"
7-
version = "0.6.0"
8-
description = "Feel++ modelica to fmu converter package"
7+
version = "1.0.0"
8+
description = "Feel++ modelica to fmu converter package with Dymola and OpenModelica support"
99
readme = "README.md"
1010
license = { text = "MIT" }
1111
authors = [
1212
{ name = "Feel++ Consortium", email = "support@feelpp.org" },
1313
{ name = "Christophe Prud'homme", email = "christophe.prudhomme@cemosis.fr" },
1414
{ name = "Philippe Pinçon", email = "philippe.pincon@cemosis.fr" }
1515
]
16-
keywords = ["modelica", "fmu", "fmi", "dymola", "simulation"]
16+
keywords = ["modelica", "fmu", "fmi", "dymola", "openmodelica", "simulation"]
1717
requires-python = ">=3.8.1"
1818
classifiers = [
19-
"Development Status :: 4 - Beta",
19+
"Development Status :: 5 - Production/Stable",
2020
"Intended Audience :: Science/Research",
2121
"Intended Audience :: Developers",
2222
"Programming Language :: Python :: 3",
@@ -47,6 +47,14 @@ Documentation = "https://feelpp.github.io/mo2fmu/"
4747

4848
# Optional dependencies for testing and development.
4949
[project.optional-dependencies]
50+
# OpenModelica backend support (alternative to Dymola)
51+
openmodelica = [
52+
"OMPython>=3.4.0",
53+
]
54+
# FMU simulation support (for testing Model Exchange with CVODE solver)
55+
simulation = [
56+
"fmpy>=0.3.0",
57+
]
5058
test = [
5159
"pytest>=7.0",
5260
"pytest-cov>=4.0",
@@ -66,7 +74,7 @@ lint = [
6674
"isort>=5.12",
6775
]
6876
all = [
69-
"feelpp-mo2fmu[test,dev,lint]",
77+
"feelpp-mo2fmu[openmodelica,simulation,test,dev,lint]",
7078
]
7179

7280
[project.scripts]

0 commit comments

Comments
 (0)