Files
Entropyk/bindings/fmi/README.md

113 lines
5.0 KiB
Markdown

# entropyk-fmi — Export FMI 2.0 Co-Simulation (FMU)
Compile un modèle Entropyk (JSON) en une archive `.fmu` conforme FMI 2.0 Co-Simulation, embarquable sur un PLC / contrôleur industriel (Beckhoff TwinCAT, B&R, Siemens TIA, Codesys) ou testable sur PC avec fmpy / OpenModelica.
## Principe
- Le moteur Entropyk (Rust) est compilé en `cdylib` et exporte l'ABI C standard `fmi2*`.
- Le modèle JSON + la carte d'entrées/sorties (`fmu_io.json`) sont **embarqués dans le binaire** à la build (codegen) — aucun accès fichier au runtime.
- L'hôte (PLC) pilote le scheduler temps réel ; chaque `fmi2DoStep` re-resout le cycle stationnaire aux entrées courantes (co-simulation quasi-stationnaire).
## Générer un FMU
```bash
# Cible hôte (PC courant) — pour test avec fmpy
cargo run -p entropyk-cli -- export-fmu \
-c crates/cli/examples/chiller_aircooled_r134a.json \
-i bindings/fmi/examples/chiller_aircooled_io.json \
-t host \
-o target/chiller.fmu
```
### Cross-compilation (arm / x86)
Installer les cibles Rust voulues, puis :
```bash
# Linux x86_64
rustup target add x86_64-unknown-linux-gnu
cargo run -p entropyk-cli -- export-fmu -c <model.json> -i <io.json> \
-t x86_64-unknown-linux-gnu -o target/model_linux64.fmu
# Linux ARM64 (aarch64)
rustup target add aarch64-unknown-linux-gnu
cargo run -p entropyk-cli -- export-fmu -c <model.json> -i <io.json> \
-t aarch64-unknown-linux-gnu -o target/model_aarch64.fmu
# Linux ARM32 (Cortex-A, hard-float)
rustup target add arm-unknown-linux-gnueabihf
cargo run -p entropyk-cli -- export-fmu -c <model.json> -i <io.json> \
-t arm-unknown-linux-gnueabihf -o target/model_arm32.fmu
# Windows x86_64 (PLC TwinCAT sur IPC Windows)
rustup target add x86_64-pc-windows-msvc
cargo run -p entropyk-cli -- export-fmu -c <model.json> -i <io.json> \
-t x86_64-pc-windows-msvc -o target/model_win64.fmu
```
Le dossier `binaries/<platform>/` est choisi automatiquement depuis le triple cible :
| Triple cible | Dossier FMI |
|--------------|-------------|
| `x86_64-unknown-linux-gnu` / `musl` | `linux64` |
| `aarch64-unknown-linux-gnu` / `musl` | `linuxaarch64` |
| `arm-unknown-linux-gnueabihf` | `linuxarm32` |
| `x86_64-pc-windows-msvc` / `gnu` | `win64` |
| `x86_64-apple-darwin` / `aarch64-apple-darwin` | `darwin64` |
> Cross-compiler Linux depuis Windows : installez les linkers croisés (ex. `aarch64-linux-gnu-gcc`) et configurez `[target.<triple>] linker = "..."` dans `~/.cargo/config.toml`. Le codegen du crate staged hérite de la config cargo de l'utilisateur.
## Contenu de l'archive `.fmu`
```
modelDescription.xml (déclare les entrées/sorties, le GUID, le modelIdentifier)
binaries/<platform>/entropyk_fmi.{so|dll|dylib}
resources/config.json (le modèle Entropyk, pour référence)
resources/fmu_io.json (la carte d'entrées/sorties)
```
## Carte d'entrées/sorties (`fmu_io.json`)
Déclare quelles variables le PLC peut écrire (entrées) et lire (sorties). Les `valueReference` sont attribués dans l'ordre : entrées d'abord (`0..n_inputs`), puis sorties (`n_inputs..`).
```json
{
"inputs": [
{ "name": "T_air_c", "component": "cond_air_in", "param": "t_dry_c", "kind": "input" },
{ "name": "m_air", "component": "cond_air_in", "param": "m_flow_kg_s", "kind": "input" }
],
"outputs": [
{ "name": "COP", "kind": "cop" },
{ "name": "Q_cool_kW", "kind": "q_cooling_kw" },
{ "name": "P_kW", "kind": "compressor_power_kw" },
{ "name": "P_evap_bar","kind": "pressure_bar", "edge": 3 }
]
}
```
`kind` pour les sorties : `cop`, `q_cooling_kw`, `q_heating_kw`, `compressor_power_kw`, `pressure_bar`, `enthalpy_kj_kg`, `mass_flow_kg_s`. Les trois derniers nécessitent `edge` (index d'arête).
## Mode dev (sans codegen)
Pour itérer sans recompiler le FMU à chaque changement de modèle, le runtime peut lire le modèle depuis des variables d'environnement au lieu de la version embarquée :
```bash
cargo build -p entropyk-fmi
export ENTROPYK_FMU_MODEL=crates/cli/examples/chiller_aircooled_r134a.json
export ENTROPYK_FMU_IO=bindings/fmi/examples/chiller_aircooled_io.json
# charger target/debug/entropyk_fmi.{so|dll} dans fmpy comme FMU Co-Sim
```
## Test rapide avec fmpy (Python)
```bash
uv pip install fmpy
uv run python -c "from fmpy import simulate_fmu; simulate_fmu('target/chiller.fmu', stop_time=1.0)"
```
## Limites actuelles (skeleton)
- **Pas de warm-start** : chaque `doStep` reconstruit le graphe `System` et relance un Newton à froid. Pour un cycle 100 ms c'est acceptable ; l'optimisation (réutiliser l'état précédent + le `System` construit) nécessite de scinder `execute_simulation` en `build_system` + `solve_warm` — TODO.
- **Backend fluide** : le FMU embarque actuellement le backend déclaré dans le JSON (CoolProp inclus). Pour un petit MCU, préférer le backend **tabulaire** (tables précalculées hors-ligne) ; vérifier la couverture de la plage de fonctionnement.
- **Itérations bornées** : à configurer via `solver.max_iterations` dans le modèle pour garantir un budget temps réel par pas.