modelica 0.0.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.
- modelica-0.0.1/.gitignore +11 -0
- modelica-0.0.1/CHANGELOG.md +17 -0
- modelica-0.0.1/LICENSE +21 -0
- modelica-0.0.1/PKG-INFO +106 -0
- modelica-0.0.1/README.md +73 -0
- modelica-0.0.1/docs/architecture.md +110 -0
- modelica-0.0.1/docs/changelog.md +3 -0
- modelica-0.0.1/docs/index.md +31 -0
- modelica-0.0.1/pyproject.toml +123 -0
- modelica-0.0.1/src/modelica/__init__.py +21 -0
- modelica-0.0.1/src/modelica/py.typed +0 -0
- modelica-0.0.1/tests/test_version.py +22 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. Versions follow
|
|
4
|
+
[semantic versioning](https://semver.org/); the version in `pyproject.toml` is the single
|
|
5
|
+
source of truth and is bumped automatically when shipped source changes.
|
|
6
|
+
|
|
7
|
+
## 0.0.1 — unreleased
|
|
8
|
+
|
|
9
|
+
Project restart. The 2010 Python 2 / pyparsing prototype is retired (it remains in git
|
|
10
|
+
history); nothing from it is carried forward.
|
|
11
|
+
|
|
12
|
+
- Claim the `modelica` distribution name on PyPI.
|
|
13
|
+
- Repository moved from GitHub to GitLab (`gitlab.com/jorgeecardona/pymodelica`).
|
|
14
|
+
- Toolchain: uv + moon pinned via proto; ruff (`select = ["ALL"]`) and pyright strict.
|
|
15
|
+
- Single-job GitLab CI driven by `moon run :ci`; PyPI releases via OIDC Trusted
|
|
16
|
+
Publishing; docs on GitLab Pages.
|
|
17
|
+
- Python 3.11+ only.
|
modelica-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jorge Cardona
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
modelica-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: modelica
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Pure-Python Modelica toolchain: parse, flatten, simulate, and exchange via FMI 3.0 and SSP 2.0
|
|
5
|
+
Project-URL: Homepage, https://gitlab.com/jorgeecardona/pymodelica
|
|
6
|
+
Project-URL: Repository, https://gitlab.com/jorgeecardona/pymodelica
|
|
7
|
+
Project-URL: Changelog, https://gitlab.com/jorgeecardona/pymodelica/-/blob/main/CHANGELOG.md
|
|
8
|
+
Project-URL: Documentation, https://jorgeecardona.gitlab.io/pymodelica/
|
|
9
|
+
Author-email: Jorge Cardona <jorgeecardona@gmail.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: co-simulation,dae,digital-twin,fmi,fmu,modelica,simulation,ssp,system-modeling
|
|
13
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Operating System :: MacOS
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Provides-Extra: docs
|
|
25
|
+
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
|
|
26
|
+
Requires-Dist: mkdocs>=1.6; extra == 'docs'
|
|
27
|
+
Provides-Extra: sim
|
|
28
|
+
Requires-Dist: numpy>=2.0; extra == 'sim'
|
|
29
|
+
Requires-Dist: scipy>=1.13; extra == 'sim'
|
|
30
|
+
Provides-Extra: sundials
|
|
31
|
+
Requires-Dist: scikit-sundae>=1.0; extra == 'sundials'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# modelica
|
|
35
|
+
|
|
36
|
+
A pure-Python Modelica toolchain: **parse** Modelica, **flatten** it to a DAE, **simulate**
|
|
37
|
+
it, and interoperate with the two Modelica Association exchange standards — **FMI 3.0**
|
|
38
|
+
for single components and **SSP 2.0** for systems of them.
|
|
39
|
+
|
|
40
|
+
> Distribution name is `modelica`; the git repo keeps its historical name `pymodelica`.
|
|
41
|
+
> (PyPI's `pymodelica` is held by an abandoned Modelon/JModelica.org upload.)
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install modelica # core: parse + model structure, zero dependencies
|
|
45
|
+
pip install "modelica[sim]" # + numpy/scipy for simulation
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Status
|
|
49
|
+
|
|
50
|
+
Pre-alpha. This is a **full rewrite** of a 2010 Python 2 experiment — none of that code
|
|
51
|
+
survives, only the goal. Python 3.11+.
|
|
52
|
+
|
|
53
|
+
## Why
|
|
54
|
+
|
|
55
|
+
The Python side of Modelica is split: [FMPy](https://github.com/CATIA-Systems/FMPy) and
|
|
56
|
+
[PyFMI](https://github.com/modelon-community/PyFMI) *consume* FMUs that some other tool
|
|
57
|
+
compiled, and the tools that actually compile Modelica (Dymola, OpenModelica, JModelica)
|
|
58
|
+
are large non-Python programs. Nothing in Python takes Modelica source all the way to a
|
|
59
|
+
running simulation, and nothing treats the model — flat equations, the incidence structure,
|
|
60
|
+
the index — as an ordinary Python data structure you can inspect and rewrite.
|
|
61
|
+
|
|
62
|
+
That gap is the project: a readable, dependency-light implementation where every stage is a
|
|
63
|
+
value you can hold.
|
|
64
|
+
|
|
65
|
+
## Layers
|
|
66
|
+
|
|
67
|
+
Each layer is usable without the ones above it.
|
|
68
|
+
|
|
69
|
+
| Module | Does |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| `modelica.lang` | Modelica source → tokens → AST (hand-written lexer/parser, positions carried for diagnostics) |
|
|
72
|
+
| `modelica.ir` | AST → flat model (variables, equations, expression IR), then matching / BLT sorting / index reduction |
|
|
73
|
+
| `modelica.sim` | flat model → ODE/DAE problem, solver backends, event (zero-crossing) handling |
|
|
74
|
+
| `modelica.fmi` | FMI 3.0 — read and simulate an FMU; export a flat model as one |
|
|
75
|
+
| `modelica.ssp` | SSP 2.0 — `.ssd`/`.ssv`/`.ssb` inside a `.ssp`, and a co-simulation master over the components |
|
|
76
|
+
|
|
77
|
+
See [the architecture notes](docs/architecture.md) for the data model and the order things
|
|
78
|
+
get built in.
|
|
79
|
+
|
|
80
|
+
## Development
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
make install-hooks # once after cloning: pre-commit (auto version bump + ruff), pre-push (full check)
|
|
84
|
+
make check # lint + typecheck + test, exactly what CI gates on
|
|
85
|
+
make docs # build the mkdocs site strictly
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The toolchain is pinned in `.prototools` (moon + uv) — `proto install` brings up
|
|
89
|
+
everything. All task ordering lives in `moon.yml`; CI is a single `moon run :ci`.
|
|
90
|
+
|
|
91
|
+
## Releasing
|
|
92
|
+
|
|
93
|
+
There is no manual release step. `pyproject.toml`'s `version` is the single source of
|
|
94
|
+
truth:
|
|
95
|
+
|
|
96
|
+
* the pre-commit hook auto-bumps the patch version whenever `src/**/*.py` changes;
|
|
97
|
+
* `scripts/ci-version-guard` fails the pipeline if shipped source moved without a bump
|
|
98
|
+
(the non-bypassable counterpart);
|
|
99
|
+
* on `main`, `moon run :release` publishes to PyPI **only if that version isn't there
|
|
100
|
+
yet**, via GitLab OIDC Trusted Publishing — no API token is stored anywhere.
|
|
101
|
+
|
|
102
|
+
Docs are published to GitLab Pages from the same pipeline.
|
|
103
|
+
|
|
104
|
+
## License
|
|
105
|
+
|
|
106
|
+
MIT © Jorge Cardona
|
modelica-0.0.1/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# modelica
|
|
2
|
+
|
|
3
|
+
A pure-Python Modelica toolchain: **parse** Modelica, **flatten** it to a DAE, **simulate**
|
|
4
|
+
it, and interoperate with the two Modelica Association exchange standards — **FMI 3.0**
|
|
5
|
+
for single components and **SSP 2.0** for systems of them.
|
|
6
|
+
|
|
7
|
+
> Distribution name is `modelica`; the git repo keeps its historical name `pymodelica`.
|
|
8
|
+
> (PyPI's `pymodelica` is held by an abandoned Modelon/JModelica.org upload.)
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install modelica # core: parse + model structure, zero dependencies
|
|
12
|
+
pip install "modelica[sim]" # + numpy/scipy for simulation
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Status
|
|
16
|
+
|
|
17
|
+
Pre-alpha. This is a **full rewrite** of a 2010 Python 2 experiment — none of that code
|
|
18
|
+
survives, only the goal. Python 3.11+.
|
|
19
|
+
|
|
20
|
+
## Why
|
|
21
|
+
|
|
22
|
+
The Python side of Modelica is split: [FMPy](https://github.com/CATIA-Systems/FMPy) and
|
|
23
|
+
[PyFMI](https://github.com/modelon-community/PyFMI) *consume* FMUs that some other tool
|
|
24
|
+
compiled, and the tools that actually compile Modelica (Dymola, OpenModelica, JModelica)
|
|
25
|
+
are large non-Python programs. Nothing in Python takes Modelica source all the way to a
|
|
26
|
+
running simulation, and nothing treats the model — flat equations, the incidence structure,
|
|
27
|
+
the index — as an ordinary Python data structure you can inspect and rewrite.
|
|
28
|
+
|
|
29
|
+
That gap is the project: a readable, dependency-light implementation where every stage is a
|
|
30
|
+
value you can hold.
|
|
31
|
+
|
|
32
|
+
## Layers
|
|
33
|
+
|
|
34
|
+
Each layer is usable without the ones above it.
|
|
35
|
+
|
|
36
|
+
| Module | Does |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| `modelica.lang` | Modelica source → tokens → AST (hand-written lexer/parser, positions carried for diagnostics) |
|
|
39
|
+
| `modelica.ir` | AST → flat model (variables, equations, expression IR), then matching / BLT sorting / index reduction |
|
|
40
|
+
| `modelica.sim` | flat model → ODE/DAE problem, solver backends, event (zero-crossing) handling |
|
|
41
|
+
| `modelica.fmi` | FMI 3.0 — read and simulate an FMU; export a flat model as one |
|
|
42
|
+
| `modelica.ssp` | SSP 2.0 — `.ssd`/`.ssv`/`.ssb` inside a `.ssp`, and a co-simulation master over the components |
|
|
43
|
+
|
|
44
|
+
See [the architecture notes](docs/architecture.md) for the data model and the order things
|
|
45
|
+
get built in.
|
|
46
|
+
|
|
47
|
+
## Development
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
make install-hooks # once after cloning: pre-commit (auto version bump + ruff), pre-push (full check)
|
|
51
|
+
make check # lint + typecheck + test, exactly what CI gates on
|
|
52
|
+
make docs # build the mkdocs site strictly
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The toolchain is pinned in `.prototools` (moon + uv) — `proto install` brings up
|
|
56
|
+
everything. All task ordering lives in `moon.yml`; CI is a single `moon run :ci`.
|
|
57
|
+
|
|
58
|
+
## Releasing
|
|
59
|
+
|
|
60
|
+
There is no manual release step. `pyproject.toml`'s `version` is the single source of
|
|
61
|
+
truth:
|
|
62
|
+
|
|
63
|
+
* the pre-commit hook auto-bumps the patch version whenever `src/**/*.py` changes;
|
|
64
|
+
* `scripts/ci-version-guard` fails the pipeline if shipped source moved without a bump
|
|
65
|
+
(the non-bypassable counterpart);
|
|
66
|
+
* on `main`, `moon run :release` publishes to PyPI **only if that version isn't there
|
|
67
|
+
yet**, via GitLab OIDC Trusted Publishing — no API token is stored anywhere.
|
|
68
|
+
|
|
69
|
+
Docs are published to GitLab Pages from the same pipeline.
|
|
70
|
+
|
|
71
|
+
## License
|
|
72
|
+
|
|
73
|
+
MIT © Jorge Cardona
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
The design rule for this rewrite: **every stage is a value you can hold.** Parsing returns
|
|
4
|
+
an AST, flattening returns a flat model, causalization returns a sorted block structure,
|
|
5
|
+
and simulation returns trajectories — each one an ordinary, inspectable Python object
|
|
6
|
+
rather than state hidden inside a compiler. The 2010 prototype failed the other way: the
|
|
7
|
+
grammar (pyparsing) *was* the program, so there was nothing to look at between "source" and
|
|
8
|
+
"result".
|
|
9
|
+
|
|
10
|
+
Nothing here is implemented yet. This is the target, and the order it gets built in.
|
|
11
|
+
|
|
12
|
+
## The pipeline
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
Modelica source
|
|
16
|
+
│ modelica.lang hand-written lexer + recursive-descent parser
|
|
17
|
+
▼
|
|
18
|
+
AST positions carried on every node (diagnostics)
|
|
19
|
+
│ modelica.ir instantiation / flattening
|
|
20
|
+
▼
|
|
21
|
+
FlatModel variables + equations + expression IR
|
|
22
|
+
│ modelica.ir matching, BLT sorting, index reduction
|
|
23
|
+
▼
|
|
24
|
+
CausalizedModel sorted blocks, known index, states chosen
|
|
25
|
+
│ modelica.sim residual/RHS construction
|
|
26
|
+
▼
|
|
27
|
+
Problem ──► Solver ──► Result
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Two exchange formats cut across it:
|
|
31
|
+
|
|
32
|
+
* **FMI 3.0** (`modelica.fmi`) attaches at both ends — read an FMU someone else compiled
|
|
33
|
+
and simulate it through the same `Problem`/`Solver` interface, or export a
|
|
34
|
+
`CausalizedModel` as an FMU.
|
|
35
|
+
* **SSP 2.0** (`modelica.ssp`) sits above — a `.ssp` names components (usually FMUs) and
|
|
36
|
+
wires them, so it drives a co-simulation master over several `Problem`s at once.
|
|
37
|
+
|
|
38
|
+
## Layer notes
|
|
39
|
+
|
|
40
|
+
### `modelica.lang` — source → AST
|
|
41
|
+
|
|
42
|
+
Hand-written lexer and recursive-descent parser against the Modelica Language
|
|
43
|
+
Specification 3.x grammar. No parser-generator and no `pyparsing`: the grammar is stable
|
|
44
|
+
and small enough to write out, and only a hand-written parser gives usable errors
|
|
45
|
+
("expected `end <name>;` at 12:5, to close `model Foo` opened at 3:1"). AST nodes are
|
|
46
|
+
frozen dataclasses carrying source spans.
|
|
47
|
+
|
|
48
|
+
### `modelica.ir` — AST → solvable system
|
|
49
|
+
|
|
50
|
+
The interesting layer, and the one the whole project stands on.
|
|
51
|
+
|
|
52
|
+
* **Flattening** — resolve `extends`, expand components and `for`-equations, apply
|
|
53
|
+
modifications, connect `connect()` equations into their potential/flow forms. Output:
|
|
54
|
+
a `FlatModel` of typed variables and scalar equations over an expression IR.
|
|
55
|
+
* **Expression IR** — separate from the AST on purpose. The AST mirrors what was written;
|
|
56
|
+
the IR is what gets differentiated and evaluated, so it is small, typed, and closed under
|
|
57
|
+
symbolic differentiation.
|
|
58
|
+
* **Matching + BLT** — bipartite matching of equations to unknowns, then Tarjan SCC to get
|
|
59
|
+
block-lower-triangular form: which equations must be solved simultaneously and which are
|
|
60
|
+
a straight assignment sequence.
|
|
61
|
+
* **Index reduction** — Pantelides to find the structurally singular subsets, symbolic
|
|
62
|
+
differentiation of those equations, and the dummy-derivative method to select states.
|
|
63
|
+
A high-index DAE is the normal case for a physical model written with `connect()`; a
|
|
64
|
+
toolchain that cannot reduce the index cannot simulate a mechanical model at all.
|
|
65
|
+
|
|
66
|
+
### `modelica.sim` — running it
|
|
67
|
+
|
|
68
|
+
`Problem` is the interface every backend consumes: an explicit ODE where causalization
|
|
69
|
+
achieved one, a residual DAE otherwise. Backends:
|
|
70
|
+
|
|
71
|
+
* **scipy** (`sim` extra) — `solve_ivp` for ODE form, plus root-finding for the algebraic
|
|
72
|
+
blocks. The default, because it installs everywhere.
|
|
73
|
+
* **SUNDIALS IDA** via [scikit-SUNDAE](https://github.com/NREL/scikit-sundae) (`sundials`
|
|
74
|
+
extra) — real index-1 DAE integration with consistent initialization. Optional because it
|
|
75
|
+
needs a compiled SUNDIALS.
|
|
76
|
+
|
|
77
|
+
Events (zero crossings from `if`/`when`, and state events generally) are the part that
|
|
78
|
+
makes this harder than "call an integrator": the solver must stop at the crossing, the
|
|
79
|
+
model is re-initialized, and integration restarts. That is designed in from the start, not
|
|
80
|
+
bolted on.
|
|
81
|
+
|
|
82
|
+
### `modelica.fmi` — FMI 3.0
|
|
83
|
+
|
|
84
|
+
`modelDescription.xml` parsed into dataclasses (variables, causality/variability, model
|
|
85
|
+
structure, unit definitions), the FMU's shared library loaded through `ctypes`, and both
|
|
86
|
+
interface types wrapped: Model Exchange (the FMU supplies the derivatives, we integrate)
|
|
87
|
+
and Co-Simulation (the FMU integrates itself between communication points). Export goes the
|
|
88
|
+
other way: a `CausalizedModel` plus a generated `modelDescription.xml`, with the FMU's C
|
|
89
|
+
entry points backed by the Python evaluator.
|
|
90
|
+
|
|
91
|
+
### `modelica.ssp` — SSP 2.0
|
|
92
|
+
|
|
93
|
+
A `.ssp` is a zip: `SystemStructure.ssd` (components, connectors, connections, possibly
|
|
94
|
+
nested systems), `.ssv` parameter sets, `.ssb` bindings. Parsed into a composition graph,
|
|
95
|
+
resolved against the FMUs it references, and executed by a co-simulation master that steps
|
|
96
|
+
the components and exchanges signals at communication points. SSP 2.0 specifics that matter
|
|
97
|
+
to the data model: FMI 3.0 component support, the `structuralParameter` connector kind,
|
|
98
|
+
clocked connectors, and arrays in connectors/connections.
|
|
99
|
+
|
|
100
|
+
## Build order
|
|
101
|
+
|
|
102
|
+
1. `lang` + `ir` far enough to flatten a trivial `model` into scalar equations.
|
|
103
|
+
2. `sim` on the explicit-ODE case, scipy backend — first end-to-end simulation.
|
|
104
|
+
3. Matching/BLT, then Pantelides + dummy derivatives — first physical model with
|
|
105
|
+
`connect()`.
|
|
106
|
+
4. `fmi` import (read + simulate an existing FMU) — validates the variable/model-structure
|
|
107
|
+
data model against real files.
|
|
108
|
+
5. Events.
|
|
109
|
+
6. `fmi` export.
|
|
110
|
+
7. `ssp` composition + co-simulation master.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# modelica
|
|
2
|
+
|
|
3
|
+
Pure-Python Modelica toolchain: parse Modelica, flatten it to a DAE, simulate it, and
|
|
4
|
+
exchange models via **FMI 3.0** and **SSP 2.0**.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
pip install modelica # core: parse + model structure, zero dependencies
|
|
8
|
+
pip install "modelica[sim]" # + numpy/scipy for simulation
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
!!! warning "Pre-alpha"
|
|
12
|
+
A full rewrite of a 2010 prototype, in progress. The API is not stable and the layers
|
|
13
|
+
below are being built bottom-up. Python 3.11+.
|
|
14
|
+
|
|
15
|
+
## The layers
|
|
16
|
+
|
|
17
|
+
| Module | Does |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| `modelica.lang` | Modelica source → tokens → AST |
|
|
20
|
+
| `modelica.ir` | AST → flat model; matching, BLT sorting, index reduction |
|
|
21
|
+
| `modelica.sim` | flat model → ODE/DAE problem; solvers and events |
|
|
22
|
+
| `modelica.fmi` | FMI 3.0 — import, simulate, and export FMUs |
|
|
23
|
+
| `modelica.ssp` | SSP 2.0 — system composition and a co-simulation master |
|
|
24
|
+
|
|
25
|
+
Start with [Architecture](architecture.md) for the data model and the build order.
|
|
26
|
+
|
|
27
|
+
## Standards targeted
|
|
28
|
+
|
|
29
|
+
* **Modelica Language Specification 3.x**
|
|
30
|
+
* **FMI 3.0** — [fmi-standard.org](https://fmi-standard.org/)
|
|
31
|
+
* **SSP 2.0** — [ssp-standard.org](https://ssp-standard.org/)
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
# modelica — a pure-Python Modelica/FMI/SSP toolchain: parse Modelica, flatten it to a
|
|
3
|
+
# DAE, simulate it, and interoperate with the two Modelica Association exchange standards
|
|
4
|
+
# (FMI 3.0 for single components, SSP 2.0 for systems of them).
|
|
5
|
+
#
|
|
6
|
+
# The distribution name is `modelica`, not `pymodelica`: PyPI's `pymodelica` is held by an
|
|
7
|
+
# abandoned Modelon/JModelica.org upload (version "trunk"). The git repo keeps the
|
|
8
|
+
# historical name; the import package matches the distribution.
|
|
9
|
+
name = "modelica"
|
|
10
|
+
version = "0.0.1"
|
|
11
|
+
description = "Pure-Python Modelica toolchain: parse, flatten, simulate, and exchange via FMI 3.0 and SSP 2.0"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
# 3.11+, no compatibility shims: this is a full rewrite of a 2010 Python 2 codebase, and
|
|
14
|
+
# the modelling layer leans on 3.11 features (Self, StrEnum, exception groups for
|
|
15
|
+
# multi-error diagnostics, and the tomllib/typing niceties) rather than back-porting them.
|
|
16
|
+
requires-python = ">=3.11"
|
|
17
|
+
license = "MIT"
|
|
18
|
+
license-files = ["LICENSE"]
|
|
19
|
+
authors = [{ name = "Jorge Cardona", email = "jorgeecardona@gmail.com" }]
|
|
20
|
+
keywords = [
|
|
21
|
+
"modelica",
|
|
22
|
+
"fmi",
|
|
23
|
+
"fmu",
|
|
24
|
+
"ssp",
|
|
25
|
+
"simulation",
|
|
26
|
+
"dae",
|
|
27
|
+
"co-simulation",
|
|
28
|
+
"digital-twin",
|
|
29
|
+
"system-modeling",
|
|
30
|
+
]
|
|
31
|
+
classifiers = [
|
|
32
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
33
|
+
"Intended Audience :: Science/Research",
|
|
34
|
+
"Operating System :: POSIX :: Linux",
|
|
35
|
+
"Operating System :: MacOS",
|
|
36
|
+
"Programming Language :: Python :: 3",
|
|
37
|
+
"Programming Language :: Python :: 3.11",
|
|
38
|
+
"Programming Language :: Python :: 3.12",
|
|
39
|
+
"Programming Language :: Python :: 3.13",
|
|
40
|
+
"Topic :: Scientific/Engineering",
|
|
41
|
+
"Typing :: Typed",
|
|
42
|
+
]
|
|
43
|
+
# Deliberately dependency-free at the core. The parser is hand-written (no pyparsing —
|
|
44
|
+
# that was the 2010 design and it could not carry error positions), the FMI/SSP layers
|
|
45
|
+
# read XML from the stdlib, and numeric backends arrive as extras so `import modelica`
|
|
46
|
+
# stays cheap for tooling that only reads model structure.
|
|
47
|
+
dependencies = []
|
|
48
|
+
|
|
49
|
+
[project.optional-dependencies]
|
|
50
|
+
# Numerics for the simulation layer. scipy covers ODE + the algebraic solves; the SUNDIALS
|
|
51
|
+
# IDA binding for real (index-1) DAEs is a separate extra because it needs a compiled
|
|
52
|
+
# SUNDIALS and must not be a hard requirement of `pip install modelica`.
|
|
53
|
+
sim = ["numpy>=2.0", "scipy>=1.13"]
|
|
54
|
+
sundials = ["scikit-sundae>=1.0"]
|
|
55
|
+
# docs are an *extra* (not a uv dependency-group) so external services can install them via pip
|
|
56
|
+
docs = ["mkdocs>=1.6", "mkdocs-material>=9.5"]
|
|
57
|
+
|
|
58
|
+
[project.urls]
|
|
59
|
+
Homepage = "https://gitlab.com/jorgeecardona/pymodelica"
|
|
60
|
+
Repository = "https://gitlab.com/jorgeecardona/pymodelica"
|
|
61
|
+
Changelog = "https://gitlab.com/jorgeecardona/pymodelica/-/blob/main/CHANGELOG.md"
|
|
62
|
+
Documentation = "https://jorgeecardona.gitlab.io/pymodelica/"
|
|
63
|
+
|
|
64
|
+
[build-system]
|
|
65
|
+
requires = ["hatchling"]
|
|
66
|
+
build-backend = "hatchling.build"
|
|
67
|
+
|
|
68
|
+
[tool.hatch.build.targets.wheel]
|
|
69
|
+
packages = ["src/modelica"]
|
|
70
|
+
|
|
71
|
+
[tool.hatch.build.targets.sdist]
|
|
72
|
+
include = ["src", "tests", "docs", "README.md", "CHANGELOG.md", "LICENSE"]
|
|
73
|
+
|
|
74
|
+
[dependency-groups]
|
|
75
|
+
dev = [
|
|
76
|
+
"ruff>=0.6",
|
|
77
|
+
"pyright>=1.1.390",
|
|
78
|
+
"pytest>=8",
|
|
79
|
+
"pytest-cov>=6",
|
|
80
|
+
"numpy>=2.0",
|
|
81
|
+
"scipy>=1.13",
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
[tool.pytest.ini_options]
|
|
85
|
+
testpaths = ["tests"]
|
|
86
|
+
|
|
87
|
+
[tool.ruff]
|
|
88
|
+
line-length = 100
|
|
89
|
+
target-version = "py311"
|
|
90
|
+
src = ["src", "tests"]
|
|
91
|
+
|
|
92
|
+
[tool.ruff.lint]
|
|
93
|
+
# Strict: everything on, each opt-out justified.
|
|
94
|
+
select = ["ALL"]
|
|
95
|
+
ignore = [
|
|
96
|
+
"E501", # line length is the formatter's job (line-length = 100)
|
|
97
|
+
"COM812", # trailing commas conflict with `ruff format` (ruff's own recommendation)
|
|
98
|
+
"D1", # not every helper owes a docstring; the ones that exist explain *why*
|
|
99
|
+
"D401", # docstrings here are narrative rationale, not imperative summaries
|
|
100
|
+
"TRY003", "EM101", "EM102", # inline exception messages; msg-variable style adds noise
|
|
101
|
+
"CPY001", # per-file copyright headers; LICENSE covers the repo
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
[tool.ruff.lint.per-file-ignores]
|
|
105
|
+
"tests/*" = [
|
|
106
|
+
"S101", # asserts are the point of tests
|
|
107
|
+
"PLR2004", # literal expectations in asserts are clearer than named constants
|
|
108
|
+
"ARG", # pytest fixture signatures are fixed; params can go unused
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
[tool.ruff.lint.pydocstyle]
|
|
112
|
+
convention = "pep257"
|
|
113
|
+
|
|
114
|
+
[tool.ruff.lint.isort]
|
|
115
|
+
known-first-party = ["modelica"]
|
|
116
|
+
|
|
117
|
+
[tool.pyright]
|
|
118
|
+
include = ["src", "tests"]
|
|
119
|
+
extraPaths = ["src"]
|
|
120
|
+
pythonVersion = "3.11"
|
|
121
|
+
typeCheckingMode = "strict"
|
|
122
|
+
venvPath = "."
|
|
123
|
+
venv = ".venv"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Pure-Python Modelica toolchain: parse, flatten, simulate, exchange.
|
|
2
|
+
|
|
3
|
+
The package is layered, and each layer is usable without the ones above it:
|
|
4
|
+
|
|
5
|
+
* ``modelica.lang`` -- Modelica source -> tokens -> AST (hand-written lexer/parser).
|
|
6
|
+
* ``modelica.ir`` -- AST -> flat model: variables, equations, an expression IR;
|
|
7
|
+
then matching/BLT sorting and index reduction down to a solvable system.
|
|
8
|
+
* ``modelica.sim`` -- the flat model as an ODE/DAE problem plus solver backends and
|
|
9
|
+
event (zero-crossing) handling.
|
|
10
|
+
* ``modelica.fmi`` -- FMI 3.0: read/simulate an existing FMU, and export a flat model
|
|
11
|
+
as one.
|
|
12
|
+
* ``modelica.ssp`` -- SSP 2.0: system composition (.ssd/.ssv/.ssb inside a .ssp) and a
|
|
13
|
+
co-simulation master over the components it names.
|
|
14
|
+
|
|
15
|
+
``import modelica`` pulls in no third-party dependency; numerics live behind the ``sim``
|
|
16
|
+
extra so that tooling which only reads model *structure* stays cheap to install.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
__version__ = "0.0.1"
|
|
20
|
+
|
|
21
|
+
__all__ = ["__version__"]
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""The version in ``modelica.__version__`` mirrors pyproject's.
|
|
2
|
+
|
|
3
|
+
scripts/bump-version rewrites both, and this is what catches it when only one of them moves.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import re
|
|
9
|
+
import tomllib
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
import modelica
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_version_matches_pyproject() -> None:
|
|
16
|
+
pyproject = Path(__file__).resolve().parent.parent / "pyproject.toml"
|
|
17
|
+
data = tomllib.loads(pyproject.read_text(encoding="utf-8"))
|
|
18
|
+
assert modelica.__version__ == data["project"]["version"]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_version_is_semver() -> None:
|
|
22
|
+
assert re.fullmatch(r"\d+\.\d+\.\d+", modelica.__version__)
|