268 lines
6.5 KiB
Markdown
268 lines
6.5 KiB
Markdown
# Story 10.6: Mise à jour des Bindings Python
|
|
|
|
**Epic:** 10 - Enhanced Boundary Conditions
|
|
**Priorité:** P1-HIGH
|
|
**Estimation:** 2h
|
|
**Statut:** backlog
|
|
**Dépendances:** Stories 10-2, 10-3, 10-4
|
|
|
|
---
|
|
|
|
## Story
|
|
|
|
> En tant qu'utilisateur Python de la librairie Entropyk,
|
|
> Je veux accéder aux nouveaux types de conditions aux limites via l'API Python,
|
|
> Afin de pouvoir utiliser les fonctionnalités avancées (concentration glycol, titre, psychrométrie).
|
|
|
|
---
|
|
|
|
## Contexte
|
|
|
|
Les bindings Python (via PyO3) doivent être mis à jour pour exposer:
|
|
|
|
1. Les nouveaux types physiques (`Concentration`, `VolumeFlow`, `RelativeHumidity`, `VaporQuality`)
|
|
2. Les nouveaux composants (`RefrigerantSource`, `BrineSource`, `AirSource`, etc.)
|
|
|
|
---
|
|
|
|
## Spécifications Techniques
|
|
|
|
### 1. Exposer les Nouveaux Types Physiques
|
|
|
|
```python
|
|
# bindings/python/entropyk/core.py
|
|
|
|
class Concentration:
|
|
"""Concentration massique en % (0-100)"""
|
|
|
|
@staticmethod
|
|
def from_percent(value: float) -> 'Concentration':
|
|
"""Crée une concentration depuis un pourcentage."""
|
|
pass
|
|
|
|
def to_percent(self) -> float:
|
|
"""Retourne la concentration en pourcentage."""
|
|
pass
|
|
|
|
def to_mass_fraction(self) -> float:
|
|
"""Retourne la fraction massique (0-1)."""
|
|
pass
|
|
|
|
|
|
class VolumeFlow:
|
|
"""Débit volumique en m³/s"""
|
|
|
|
@staticmethod
|
|
def from_m3_per_s(value: float) -> 'VolumeFlow':
|
|
pass
|
|
|
|
@staticmethod
|
|
def from_l_per_min(value: float) -> 'VolumeFlow':
|
|
pass
|
|
|
|
def to_m3_per_s(self) -> float:
|
|
pass
|
|
|
|
def to_l_per_min(self) -> float:
|
|
pass
|
|
|
|
|
|
class RelativeHumidity:
|
|
"""Humidité relative en % (0-100)"""
|
|
|
|
@staticmethod
|
|
def from_percent(value: float) -> 'RelativeHumidity':
|
|
pass
|
|
|
|
def to_percent(self) -> float:
|
|
pass
|
|
|
|
def to_fraction(self) -> float:
|
|
pass
|
|
|
|
|
|
class VaporQuality:
|
|
"""Titre (vapor quality) pour fluides frigorigènes (0-1)"""
|
|
|
|
@staticmethod
|
|
def from_fraction(value: float) -> 'VaporQuality':
|
|
pass
|
|
|
|
def to_fraction(self) -> float:
|
|
pass
|
|
|
|
def to_percent(self) -> float:
|
|
pass
|
|
```
|
|
|
|
### 2. Exposer les Nouveaux Composants
|
|
|
|
```python
|
|
# bindings/python/entropyk/components.py
|
|
|
|
class RefrigerantSource:
|
|
"""Source pour fluides frigorigènes compressibles."""
|
|
|
|
@staticmethod
|
|
def new(
|
|
fluid_id: str,
|
|
pressure: Pressure,
|
|
enthalpy: Enthalpy,
|
|
outlet: ConnectedPort,
|
|
) -> 'RefrigerantSource':
|
|
"""Crée une source avec pression et enthalpie fixées."""
|
|
pass
|
|
|
|
@staticmethod
|
|
def with_vapor_quality(
|
|
fluid_id: str,
|
|
pressure: Pressure,
|
|
vapor_quality: VaporQuality,
|
|
outlet: ConnectedPort,
|
|
) -> 'RefrigerantSource':
|
|
"""Crée une source avec pression et titre fixés."""
|
|
pass
|
|
|
|
def set_mass_flow(self, mass_flow: MassFlow) -> None:
|
|
"""Définit le débit massique imposé."""
|
|
pass
|
|
|
|
|
|
class BrineSource:
|
|
"""Source pour fluides caloporteurs liquides."""
|
|
|
|
@staticmethod
|
|
def water(
|
|
temperature: Temperature,
|
|
pressure: Pressure,
|
|
outlet: ConnectedPort,
|
|
) -> 'BrineSource':
|
|
"""Crée une source d'eau pure."""
|
|
pass
|
|
|
|
@staticmethod
|
|
def glycol_mixture(
|
|
fluid_id: str,
|
|
concentration: Concentration,
|
|
temperature: Temperature,
|
|
pressure: Pressure,
|
|
outlet: ConnectedPort,
|
|
) -> 'BrineSource':
|
|
"""Crée une source de mélange eau-glycol."""
|
|
pass
|
|
|
|
|
|
class AirSource:
|
|
"""Source pour air humide."""
|
|
|
|
@staticmethod
|
|
def from_dry_bulb_rh(
|
|
temperature_dry: Temperature,
|
|
relative_humidity: RelativeHumidity,
|
|
pressure: Pressure,
|
|
outlet: ConnectedPort,
|
|
) -> 'AirSource':
|
|
"""Crée une source avec température sèche et humidité relative."""
|
|
pass
|
|
|
|
@staticmethod
|
|
def from_dry_and_wet_bulb(
|
|
temperature_dry: Temperature,
|
|
temperature_wet_bulb: Temperature,
|
|
pressure: Pressure,
|
|
outlet: ConnectedPort,
|
|
) -> 'AirSource':
|
|
"""Crée une source avec températures sèche et bulbe humide."""
|
|
pass
|
|
|
|
def specific_enthalpy(self) -> Enthalpy:
|
|
"""Retourne l'enthalpie spécifique de l'air humide."""
|
|
pass
|
|
|
|
def humidity_ratio(self) -> float:
|
|
"""Retourne le rapport d'humidité."""
|
|
pass
|
|
```
|
|
|
|
---
|
|
|
|
## Fichiers à Modifier
|
|
|
|
| Fichier | Action |
|
|
|---------|--------|
|
|
| `bindings/python/src/core.rs` | Ajouter bindings pour nouveaux types |
|
|
| `bindings/python/src/components.rs` | Ajouter bindings pour nouveaux composants |
|
|
| `bindings/python/src/lib.rs` | Exporter les nouveaux types |
|
|
| `bindings/python/tests/test_boundary.py` | Tests pour nouveaux types |
|
|
|
|
---
|
|
|
|
## Critères d'Acceptation
|
|
|
|
- [ ] `Concentration` accessible depuis Python
|
|
- [ ] `VolumeFlow` accessible depuis Python
|
|
- [ ] `RelativeHumidity` accessible depuis Python
|
|
- [ ] `VaporQuality` accessible depuis Python
|
|
- [ ] `RefrigerantSource` et `RefrigerantSink` accessibles
|
|
- [ ] `BrineSource` et `BrineSink` accessibles
|
|
- [ ] `AirSource` et `AirSink` accessibles
|
|
- [ ] Tests Python passent
|
|
- [ ] Documentation Python générée
|
|
|
|
---
|
|
|
|
## Tests Requis
|
|
|
|
```python
|
|
# bindings/python/tests/test_boundary.py
|
|
|
|
def test_concentration():
|
|
c = Concentration.from_percent(30.0)
|
|
assert c.to_percent() == 30.0
|
|
assert c.to_mass_fraction() == 0.3
|
|
|
|
def test_vapor_quality():
|
|
vq = VaporQuality.from_fraction(0.5)
|
|
assert vq.to_fraction() == 0.5
|
|
assert vq.to_percent() == 50.0
|
|
|
|
def test_refrigerant_source():
|
|
source = RefrigerantSource.new(
|
|
"R410A",
|
|
Pressure.from_pascals(1e6),
|
|
Enthalpy.from_joules_per_kg(280000),
|
|
port
|
|
)
|
|
assert source is not None
|
|
|
|
def test_brine_source_glycol():
|
|
source = BrineSource.glycol_mixture(
|
|
"MEG",
|
|
Concentration.from_percent(30.0),
|
|
Temperature.from_celsius(10.0),
|
|
Pressure.from_pascals(3e5),
|
|
port
|
|
)
|
|
assert source is not None
|
|
|
|
def test_air_source_psychrometrics():
|
|
source = AirSource.from_dry_bulb_rh(
|
|
Temperature.from_celsius(25.0),
|
|
RelativeHumidity.from_percent(50.0),
|
|
Pressure.from_pascals(101325),
|
|
port
|
|
)
|
|
h = source.specific_enthalpy()
|
|
w = source.humidity_ratio()
|
|
assert h is not None
|
|
assert w > 0
|
|
```
|
|
|
|
---
|
|
|
|
## Références
|
|
|
|
- [Architecture Document](../../plans/boundary-condition-refactoring-architecture.md)
|
|
- [Story 10-1: Nouveaux types physiques](./10-1-new-physical-types.md)
|
|
- [PyO3 Documentation](https://pyo3.rs/)
|