# Entropyk CLI

Interface en ligne de commande pour lancer, valider et noter des simulations thermodynamiques à partir de fichiers JSON.

Binaire : `entropyk-cli` · Crate : `crates/cli` · Exemples : `crates/cli/examples/`

Le README racine ([`../../README.md`](../../README.md)) décrit l’architecture globale, les composants et le solveur. Ce document se concentre sur **l’usage CLI**.

---

## Installation

```bash
cargo build --release -p entropyk-cli

# Binaire
./target/release/entropyk-cli --help          # Linux / macOS
.\target\release\entropyk-cli.exe --help      # Windows
```

Ou sans installer :

```bash
cargo run -p entropyk-cli -- <sous-commande> ...
```

Flags globaux : `-v` / `--verbose`, `-q` / `--quiet`.

---

## Sous-commandes

| Commande | Rôle |
|----------|------|
| `run` | Une simulation depuis un JSON |
| `batch` | Un dossier de configs, en parallèle |
| `validate` | Vérifie la config (parse / topologie) |
| `qualify` | Qualification HX (régime frigorigène fixe) |
| `rate` | IPLV (AHRI 550/590) / ESEER |
| `scop` | SCOP EN 14825 (bins chauffage) |
| `seer` | SEER EN 14825 (bins froid) |
| `schema` | Émet le JSON Schema du Model IR |

### Exemples

```bash
# Simulation unique
cargo run -p entropyk-cli -- run \
  --config crates/cli/examples/chiller_aircooled_r134a.json \
  --output result.json

# Validation
cargo run -p entropyk-cli -- validate --config mon_cycle.json

# Batch (4 workers)
cargo run -p entropyk-cli -- batch -d ./scenarios/ -p 4 -O results.json

# Rating IPLV
cargo run -p entropyk-cli -- rate -c crates/cli/examples/rate_chiller_iplv_ahri.json

# SCOP
cargo run -p entropyk-cli -- scop -c crates/cli/examples/scop_heatpump_r134a.json

# Schema
cargo run -p entropyk-cli -- schema -o model-ir.schema.json
```

---

## Pipeline de `run`

1. Parse `ScenarioConfig` (fluide, circuits, edges, controls, solver)
2. Pour chaque composant : `create_component` (`crates/cli/src/run.rs`)
3. Câblage des arêtes `nom:port` → `nom:port`
4. `finalize()` + **porte DoF** (système carré obligatoire)
5. Estimation initiale (frontières + pressions haute/basse initialisées par étages si `emergent_pressure`)
6. Solve : `newton` | `picard` | `fallback`
7. Sortie JSON : états, performances, `dof`, erreurs / `failure_diagnostics`

---

## Format de configuration

### Structure racine

```json
{
  "name": "Mon chiller",
  "description": "optionnel",
  "fluid": "R134a",
  "fluid_backend": "CoolProp",
  "circuits": [ { "id": 0, "components": [], "edges": [] } ],
  "controls": [],
  "thermal_couplings": [],
  "solver": {
    "strategy": "newton",
    "max_iterations": 300,
    "tolerance": 1e-6
  }
}
```

| Champ | Description |
|-------|-------------|
| `fluid` | Frigorigène principal du circuit (ex. `R134a`, `R410A`) |
| `fluid_backend` | `CoolProp` (défaut sérieux), Tabular, etc. |
| `circuits[]` | Un ou plusieurs circuits (id 0…n) |
| `components[]` | Objets avec `type`, `name`, + paramètres |
| `edges[]` | `{ "from": "comp:outlet", "to": "cond:inlet" }` |
| `controls[]` | Boucles inverse / SaturatedController (optionnel) |
| `solver.strategy` | `newton` (**défaut**), `picard`, `fallback` |

### Exemple moderne (chiller air, 4 ports)

Voir `examples/chiller_aircooled_r134a.json` — pattern recommandé :

- `IsentropicCompressor` + `emergent_pressure`
- `Condenser` / `Evaporator` avec secondaires `AirSource`/`BrineSource` → HX → sinks
- `IsenthalpicExpansionValve` isenthalpique (sans orifice sauf besoin)
- Sources : Fixed T + Fixed ṁ + **Free P** ; sinks : Fixed P

```bash
cargo run -p entropyk-cli -- run \
  -c crates/cli/examples/chiller_aircooled_r134a.json
```

---

## Types de composants CLI

Chaînes `type` reconnues par `create_component` (liste non exhaustive — voir le match dans `src/run.rs`).

### Compresseurs

| Type | Paramètres utiles |
|------|-------------------|
| `IsentropicCompressor` | `displacement_m3`, `speed_hz`, `volumetric_efficiency`, `isentropic_efficiency`, `emergent_pressure` |
| `Compressor` | Cartes AHRI 540 (`m1`…`m10`) ou SST/SDT |
| `ScrewEconomizerCompressor` / `ScrewCompressor` | Courbes SST/SDT, VFD, slide valve |
| `CentrifugalCompressor` | `diameter_m`, `speed_rpm`, γ, R |

### Détente

| Type | Paramètres utiles | Attention |
|------|-------------------|-----------|
| `IsenthalpicExpansionValve` / `EXV` | `emergent_pressure`, `t_evap_k` | Sans `orifice_kv`, **`opening` est ignoré** |
| `ExpansionValve` | `opening`, `flow_model`, `beta_m2`… | |
| `CapillaryTube` | `diameter_m`, `length_m`, `n_segments` | |
| `ReversingValve` / `FourWayValve` | `mode`, `pressure_drop_pa` | |
| `BypassValve` | `opening`, `cv` | |

**EXV orifice** (débit physique) :

```json
{
  "type": "IsenthalpicExpansionValve",
  "name": "exv",
  "emergent_pressure": true,
  "orifice_kv": 2.0e-6,
  "opening": 0.6,
  "fix_opening": true
}
```

Loi : `ṁ = Kv · opening · √(2 · ρ · max(ΔP, 0))`.  
Avec orifice Fixed, le CLI met le compresseur en ṁ métré. Voir `examples/chiller_r134a_exv_orifice.json`.

### Échangeurs

| Type | Paramètres utiles |
|------|-------------------|
| `Condenser` / `Evaporator` | `ua`, `emergent_pressure`, `subcooling_k` / SH, `secondary_fluid`, ΔP secondaire |
| `FloodedEvaporator` | `ua`, `quality_control` |
| `HeatExchanger` | `ua`, `hot_fluid_id`, `cold_fluid_id` (4 ports) |
| `BphxEvaporator` / `BphxCondenser` | Géométrie plaques + corrélations |
| `AirCooledCondenser`, `FinCoilCondenser`, `MchxCondenserCoil` | Bobines air / MCHX |
| `FreeCoolingExchanger` | Free-cooling eau |

Secondaire 4 ports :

```text
BrineSource/AirSource → HX:secondary_inlet → HX:secondary_outlet → BrineSink/AirSink
```

ΔP secondaire de rating (optionnel) :

```json
"secondary_rated_pressure_drop_pa": 40000,
"secondary_rated_m_flow_kg_s": 0.5
```

### Tuyauterie / machines tournantes

| Type | Notes |
|------|-------|
| `Pipe` / `RefrigerantPipe` / `WaterPipe` / `AirDuct` | `length_m`, `diameter_m` ; `pressure_drop_pa = 0` → **Darcy** L/D ; `> 0` → ΔP imposé |
| `Pump`, `Fan` | Courbes + affinity laws |
| `FlowSplitter`, `FlowMerger`, `Drum` | Jonctions / séparateur |

### Frontières

| Type | Flags Fixed/Free |
|------|------------------|
| `BrineSource` / `BrineSink` | `fix_pressure`, `fix_temperature`, `fix_mass_flow` |
| `AirSource` / `AirSink` | idem (+ psychrométrie `t_dry_c`, `rh`) |
| `RefrigerantSource` / `RefrigerantSink` | P, qualité / h, ṁ |

**Défaut recommandé (Modelica MassFlowSource_T)** : source Fixed T + Fixed ṁ + Free P ; sink Fixed P.

Voir [`docs/modelica-boundary-proof.md`](../../docs/modelica-boundary-proof.md).

### Divers

`ThermalLoad`, `HeatSource`, `Anchor` / `RefrigerantNode`, `Placeholder`.

---

## Contrôles (régulation / calibration)

```json
"controls": [
  {
    "type": "SaturatedController",
    "id": "sh_loop",
    "measure": { "component": "evap", "output": "superheat" },
    "actuator": {
      "component": "exv",
      "factor": "opening",
      "initial": 0.5,
      "min": 0.1,
      "max": 1.0
    },
    "target": 5.0
  }
]
```

Chaque boucle ajoute des inconnues d’actionneur + résidus de tracking. Le système doit rester DoF-carré (mesure FIX ↔ actionneur FREE).

---

## Stratégies solveur

| Valeur | Comportement |
|--------|--------------|
| `newton` | Newton–Raphson (défaut). Armijo activé si contrôles, orifice EXV, ou Free-P sur `BrineSource`. |
| `picard` | Substitution successive amortie (ω ≈ 0,5) |
| `fallback` | Newton → Picard si divergence → retour Newton si résidu bas |

```json
"solver": {
  "strategy": "newton",
  "max_iterations": 300,
  "tolerance": 1e-6
}
```

Si le résidu décroît lentement (Jacobien partiellement numérique sur certains HX), augmenter `max_iterations` (ex. 1000).

---

## Sortie et codes de sortie

Sortie typique JSON (`--output`) :

- `status` : `converged` / `Error` / …
- `iterations`, `state` (arêtes : ṁ, P, h…)
- `performance` (puissances, COP…)
- `dof` (équations vs inconnues)
- `error`, `failure_diagnostics` si échec après itérations

| Code | Signification |
|------|----------------|
| 0 | Succès |
| 1 | Erreur de simulation / non-convergence |
| 2 | Erreur de configuration |
| 3 | Erreur I/O |

---

## Exemples fournis (`examples/`)

| Fichier | Intérêt |
|---------|---------|
| `chiller_aircooled_r134a.json` | Chiller air 4 ports, emergent |
| `chiller_watercooled_r410a.json` | Chiller eau R410A |
| `chiller_flooded_4port_watercooled.json` | FloodedEvaporator |
| `chiller_r134a_emergent_pressure.json` | Pressions émergentes |
| `chiller_r134a_exv_orifice.json` | EXV orifice (opening physique) |
| `chiller_r134a_superheat_control.json` | Boucle SH |
| `heatpump_airsource_r410a.json` | PAC air |
| `heatpump_r410a_reversing_valve.json` | Vanne 4 voies |
| `hx_air_water_4port.json` | HX isolé |
| `bphx_evaporator_condenser.json` | Plaques brasées |
| `capillary_tube_r134a.json` | Capillaire |
| `rate_chiller_iplv_ahri.json` | Rating IPLV |
| `scop_heatpump_r134a.json` | SCOP |

---

## Pièges fréquents

1. **EXV `opening` sans effet** → il manque `orifice_kv` (sinon isenthalpique seul ; ṁ = compresseur).
2. **DoF under-constrained** → source Free P sans fermeture P sur le HX/pipe ; ou oubli de brancher le secondaire 4 ports.
3. **DoF over-constrained** → Fixed ṁ **et** Fixed P sur la même frontière ; ou double Fixed-P sans ΔP.
4. **Pipe isobare** → avec l’ancien défaut mental « ΔP=0 = rien » : aujourd’hui `pressure_drop_pa = 0` déclenche **Darcy** depuis L/D.
5. **Exemples obsolètes** cités dans d’anciennes docs (`chiller_r410a_full.json`, etc.) → utiliser la table ci-dessus.

---

## Voir aussi

- [README racine](../../README.md) — architecture, composants, solveur
- [DOCUMENTATION.md](../../DOCUMENTATION.md) — manuel technique
- [docs/CLI_TUTORIAL.md](../../docs/CLI_TUTORIAL.md) — tutoriel pas à pas
- [docs/modelica-boundary-proof.md](../../docs/modelica-boundary-proof.md) — Fixed/Free
- [docs/rating-and-seasonal-metrics.md](../../docs/rating-and-seasonal-metrics.md) — IPLV / SCOP / SEER
