Interfaces graphiques et outils visuels
EnergySystemModels contient plusieurs briques visuelles pour construire, tester et présenter des modèles énergétiques. Cette page sert de guide de travail : elle explique comment lancer le simulateur PyQt, comment lire un graphe, comment ajouter un nouveau nœud et comment documenter les résultats avec les figures réellement produites par la bibliothèque.
Vue d’ensemble
Le simulateur graphique principal est PyqtSimulator. Il s’appuie sur le
moteur NodeEditor pour manipuler des nœuds et des connexions, puis appelle
les modèles physiques de la bibliothèque : compresseur, échangeur, pompe,
batterie, humidificateur, réchauffeur, etc.
Architecture générale : la fenêtre PyQt héberge une scène NodeEditor, les nœuds enregistrés appellent les modèles EnergySystemModels, puis les valeurs sont affichées ou sauvegardées.
Le principe d’utilisation est toujours le même :
Lancer l’interface.
Créer une nouvelle scène.
Glisser des nœuds depuis la palette.
Relier les sorties aux entrées.
Renseigner les paramètres.
Évaluer le graphe ou le nœud de sortie.
Sauvegarder le projet au format
.json.
Installation et lancement
Les interfaces nécessitent PyQt5. Dans un environnement de développement,
installer aussi la bibliothèque en mode éditable ou ajouter le dossier src
au PYTHONPATH.
pip install -e .
pip install PyQt5
Depuis le dépôt source :
cd A:\OneDrive\_Github_\EnergySystemModels
$env:PYTHONPATH = "$PWD\src"
python -m PyqtSimulator.main
Le script crée une QApplication, applique le style Fusion puis ouvre
CalculatorWindow. La fenêtre contient une zone MDI et une palette de nœuds.
Chaque élément de la palette vient du registre CALC_NODES.
Dépannage rapide
Si le simulateur ne démarre pas, vérifier dans cet ordre :
PyQt5est installé dans l’environnement actif.Le
PYTHONPATHpointe bien vers...\\EnergySystemModels\\src.- Le lancement se fait depuis le dépôt
EnergySystemModelset pas depuis le dépôt documentaire.
- Le lancement se fait depuis le dépôt
Commandes de vérification (Windows PowerShell) :
cd A:\OneDrive\_Github_\EnergySystemModels
python -c "import PyQt5; print('PyQt5 OK')"
$env:PYTHONPATH = "$PWD\src"
python -c "import PyqtSimulator; print('PyqtSimulator OK')"
Symptômes fréquents et causes probables :
Symptôme |
Cause probable |
Correctif |
|---|---|---|
|
Dépendance GUI absente |
Installer |
|
|
Exporter |
Fenêtre qui s’ouvre puis se ferme immédiatement |
Environnement Python incohérent |
Réactiver le venv puis relancer la commande standard |
Interface PyqtSimulator
La fenêtre principale regroupe les éléments suivants :
NodesPalette latérale. Elle liste les classes enregistrées par
@register_node(...). Un glisser-déposer crée un nœud dans la scène.Zone de travailScène NodeEditor. Les nœuds y sont placés, déplacés et connectés.
Menu fichierCréation, ouverture et sauvegarde des graphes. Les projets sont stockés en JSON par le moteur NodeEditor.
Menu contextuelClic droit sur un nœud pour l’évaluer, le marquer invalide ou forcer le recalcul de ses descendants. Clic droit sur une connexion pour choisir le type de courbe.
Nœud OutputNœud d’affichage final. Il déclenche l’évaluation amont et présente le fluide, le débit, la pression, l’enthalpie, la température et le débit volumique.
Convention des ports
Les connexions échangent des listes Python courtes. Cette convention rend les
graphes faciles à sérialiser dans les fichiers .json.
Type de flux |
Format échangé |
Unités |
|---|---|---|
Fluide thermodynamique |
|
|
Air humide |
|
|
Les helpers de PyqtSimulator.nodes.esm_node_helpers assurent la conversion
entre ces listes et les objets de la bibliothèque :
make_fluid_port(arr)Convertit
[fluid, F, P, h]vers unFluidPort.fluid_out(port)Convertit un
FluidPortde sortie vers la liste standard.make_air_port(arr)etair_out(port)Appliquent la même logique aux ports d’air humide.
Lecture d’un graphe
Pour un graphe simple Source -> Réchauffeur -> Output :
Le nœud source fournit le fluide. Le réchauffeur convertit la liste d’entrée
en FluidPort, appelle le modèle Heater.Object puis renvoie une liste
de sortie compatible avec Output.
Exemple d’utilisation :
Ajouter un nœud
Source.Choisir le fluide, par exemple
WaterouR134a.Définir le débit, la température et la pression.
Ajouter un nœud
Réchauffeur.Renseigner
Puissance nominaleetTaux de charge.Ajouter un nœud
Output.Relier
SourceversRéchauffeur, puisRéchauffeurversOutput.Évaluer
Output.
Résultat attendu : Output affiche l’état de sortie, tandis que le nœud
Réchauffeur affiche directement la puissance transférée et la température
de sortie.
Graphes avec plusieurs sorties
Certains composants possèdent plusieurs sorties physiques. C’est le cas du
Diviseur, du Séparateur liq/vap et du Ballon de flash. Dans ces
cas, le nœud renvoie une liste de valeurs, une par socket de sortie.
Le Diviseur conserve le même fluide, la même pression et la même
enthalpie sur les deux branches. Seul le débit est réparti entre les deux
sorties selon le ratio saisi.
Exemple d’utilisation du Diviseur :
Ajouter une
Sourceavec un débit de1.0 kg/s.Ajouter un nœud
Diviseur.Régler
Fraction vers sortie 1à0.30.Ajouter deux nœuds
Output.Relier la première sortie du
DiviseurversOutput 1.Relier la deuxième sortie du
DiviseurversOutput 2.Évaluer les deux sorties.
Résultat attendu :
Branche |
Débit attendu |
Commentaire |
|---|---|---|
Sortie 1 |
|
Fraction |
Sortie 2 |
|
Fraction |
Le routage est assuré par CalcNode.getOutputValue(index). Pour un nœud à
une seule sortie, la valeur est directement [fluid, F, P, h]. Pour un nœud
multi-sorties, la valeur devient [[fluid, F1, P, h], [fluid, F2, P, h]] et
l’index du socket permet de choisir la bonne branche.
Stockage et calcul pas-à-pas
Le nœud Ballon de stockage expose le modèle MixedStorage. Il estime la
température d’un ballon mélangé après un pas de temps, à partir de la
température initiale, du volume, du débit entrant et des pertes vers
l’ambiance.
Le nœud reçoit un flux entrant, calcule l’état du ballon après dt puis
renvoie un flux de sortie dont l’enthalpie correspond à la température du
ballon.
Paramètres principaux :
Paramètre |
Signification |
Unité |
|---|---|---|
|
Volume d’eau ou de fluide dans le ballon |
m³ |
|
Température du ballon au début du pas de temps |
°C |
|
Température extérieure pour le calcul des pertes |
°C |
|
Coefficient global de pertes thermiques |
W/m²/K |
|
Surface d’échange vers l’ambiance |
m² |
|
Durée du calcul élémentaire |
s |
Exemple d’utilisation :
Créer une
Sourceavec un fluide compatible CoolProp, par exempleWater.Définir une température d’entrée supérieure à la température initiale du ballon pour simuler une charge, ou inférieure pour simuler une décharge.
Ajouter
Ballon de stockage.Renseigner
Volume,T° initiale,T° ambianteetPas de temps.Ajouter
Outputen sortie.Évaluer le graphe.
Résultats affichés localement :
T° ballonTempérature du volume mélangé après le pas de temps.
Puissance stockagePuissance moyenne stockée ou restituée pendant le pas de temps.
Limite importante : dans l’interface actuelle, le nœud crée une nouvelle
instance du modèle à chaque évaluation. Il représente donc un pas de temps
isolé depuis T° initiale. Pour simuler une série temporelle complète, il
faut mettre à jour T° initiale entre les pas ou utiliser un script Python
qui conserve l’objet MixedStorage entre deux appels à calculate().
Cycle d’évaluation
Lorsqu’un paramètre est modifié, le nœud est marqué comme sale et ses descendants doivent être recalculés. L’évaluation d’un nœud de sortie remonte le graphe jusqu’aux sources, puis propage les valeurs vers l’aval.
Les champs Qt déclenchent onInputChanged. Le nœud aval demande ensuite
l’évaluation des nœuds amont, récupère leurs valeurs et appelle son modèle
physique.
Les points importants pour l’utilisateur sont :
Un nœud sans entrée connectée devient invalide.
Une saisie numérique invalide doit être corrigée avant d’obtenir un résultat fiable.
Le nœud
Outputest le meilleur point de contrôle : il force le calcul de toute la chaîne amont.Les unités affichées ne sont pas toujours celles utilisées en interne. Par exemple, la pression circule en bar dans le graphe mais les modèles peuvent utiliser le pascal.
Créer un nouveau nœud
Pour exposer un modèle EnergySystemModels dans l’interface, utiliser de
préférence la classe ESMNode. Elle évite de réécrire l’interface Qt, la
sérialisation et les labels de résultats.
Un nœud déclaratif contient :
op_codeIdentifiant numérique unique dans
PyqtSimulator.calc_conf.op_titleNom affiché dans la palette.
iconChemin de l’icône affichée dans la liste.
INPUTSetOUTPUTSSockets d’entrée et de sortie.
Pour un composant simple,
OUTPUTS = [1]suffit. Pour un composant à deux sorties, utiliserOUTPUTS = [1, 1]et retourner une liste de deux ports dans le même ordre que les sockets.OUTPUTS = [1, 1] def evalOperation(self, input1, input2): ... self.value = [fluid_out(model.Outlet_b), fluid_out(model.Outlet_c)] return self.value
FIELDSChamps numériques affichés sous forme de
QLineEdit.CHOICESListes déroulantes affichées sous forme de
QComboBox.RESULTSLabels de sortie mis à jour par le calcul.
evalOperation(...)Code métier : lecture des entrées, appel du modèle, affichage des résultats, retour de la valeur de sortie.
Exemple réel : nœud Réchauffeur
Le nœud Réchauffeur illustre la structure recommandée.
from ThermodynamicCycles.Components import Heater
from ThermodynamicCycles.FluidPort.FluidPort import Fluid_connect
from PyqtSimulator.calc_conf import register_node, OP_NODE_HEATER
from PyqtSimulator.nodes.esm_node_helpers import ESMNode, make_fluid_port, fluid_out
@register_node(OP_NODE_HEATER)
class CalcNode_Heater(ESMNode):
icon = "icons/heating_coil.png"
op_code = OP_NODE_HEATER
op_title = "Réchauffeur"
content_label_objname = "calc_node_heater"
INPUTS = [2]
OUTPUTS = [1]
HEIGHT = 300
FIELDS = [
("q_nom", "Puissance nominale (kW)", 100.0),
("u", "Taux de charge (0-1)", 1.0),
]
RESULTS = [
("q", "Puissance transférée (kW)"),
("to", "T° sortie (°C)"),
]
def evalOperation(self, input1, input2):
a = make_fluid_port(input1)
model = Heater.Object()
Fluid_connect(model.Inlet, a)
model.Q_flow_nominal = self.num("q_nom") * 1000.0
model.u = self.num("u")
model.calculate()
self.show_result("q", "%.3f" % (model.Q_flow / 1000.0))
self.show_result("to", "%.2f" % model.To_degC)
self.value = fluid_out(model.Outlet)
return self.value
Ce modèle donne une règle générale : les champs affichés en kW ou en bar sont convertis dans les unités attendues par le modèle, puis reconvertis pour les ports ou les labels utilisateur.
Enregistrer le nœud dans la palette
Ajouter un code unique dans
PyqtSimulator.calc_conf.Décorer la classe avec
@register_node(OP_NODE_...).Placer le fichier dans
PyqtSimulator/nodes.Vérifier que le module est importé. Le fichier
nodes/__init__.pyimporte automatiquement les fichiers.pydu dossier.Relancer
PyqtSimulator. Le nœud doit apparaître dans la palette.
Exemple de réservation d’opcode :
OP_NODE_HEATER = 280
Bonnes pratiques de développement
- Utiliser des noms de champs explicites
Le libellé doit contenir l’unité :
Puissance nominale (kW),Pression sortie (bar),Rendement (-).- Limiter la logique Qt dans les nœuds
Pour les nouveaux modèles, préférer
ESMNodeet garder le code métier dansevalOperation.- Valider les unités à chaque conversion
Les ports internes des modèles utilisent souvent le pascal et le joule par kilogramme. Les graphes utilisent plutôt le bar et le kJ/kg.
- Afficher les résultats utiles localement
Un nœud de composant peut afficher ses indicateurs propres : puissance, rendement, température de sortie, humidité relative, COP, perte de charge.
- Tester avec un graphe minimal
Avant d’intégrer un composant complexe, tester
Source -> composant -> Output. Ajouter ensuite les branches multiples.- Documenter le comportement
Chaque nouveau nœud important doit avoir un exemple dans la documentation : schéma du graphe, paramètres, résultats attendus, limites et figure si une méthode
plot()existe.
Résultats et figures dans la documentation
La documentation doit distinguer trois types de visuels :
Schéma de grapheFigure pédagogique montrant les nœuds et les connexions. Ces schémas sont générés depuis
docs/source/diagrams/*.jsonpardocs/generate_diagrams.py.Table de résultatsValeurs numériques issues d’un exemple reproductible. Les unités doivent être visibles dans l’en-tête ou dans la première colonne.
Plot du modèleFigure produite par une méthode réelle de la bibliothèque : par exemple
ch.plot(),calc.plot()oucalc.plot_detail(). Il ne faut pas remplacer ces méthodes par un tracé manuel arbitraire lorsque le modèle fournit déjà sa propre fonction de visualisation.
Workflow recommandé pour une page d’exemple :
Décrire le cas étudié et les hypothèses.
Afficher le schéma des nœuds connectés.
Donner le code minimal reproductible.
Afficher les résultats dans une table.
Afficher les plots réellement générés par les fonctions du modèle.
Ajouter une courte interprétation métier.
Générer les schémas et plots
Depuis le dépôt EnergySystemModels-fr :
cd A:\OneDrive\_Github_\EnergySystemModels-fr
python docs\generate_diagrams.py
Pour les plots réellement exposés par les modèles :
cd A:\OneDrive\_Github_\EnergySystemModels-fr
$env:PYTHONPATH = "A:\OneDrive\_Github_\EnergySystemModels\src"
$env:PYTHONIOENCODING = "utf-8"
python docs\generate_model_plots.py
Le fichier generate_model_plots.py doit rester strict : il appelle les
méthodes de plot de la bibliothèque et sauvegarde les figures dans
docs/source/images. Les figures de remplacement ne sont acceptables que
pour les exemples sans méthode graphique déterministe, et elles doivent être
signalées comme telles dans le script.
Construire la documentation
cd A:\OneDrive\_Github_\EnergySystemModels-fr
python -m sphinx -b html docs\source docs\_build\html
Ouvrir ensuite docs\_build\html\gui_tools.html pour vérifier la mise en
forme. Contrôler en particulier :
Les chemins
.. figure:: images/....Les unités dans les tableaux.
La lisibilité des schémas sur une largeur réduite.
La présence des plots lorsque l’exemple appelle une méthode
plot.
Dépannage
ModuleNotFoundError: PyqtSimulatorAjouter
EnergySystemModels/srcauPYTHONPATHou installer le paquet en mode éditable.QApplicationouPyQt5introuvableInstaller
PyQt5dans l’environnement actif.CoolPropintrouvableInstaller les dépendances scientifiques utilisées par les composants thermodynamiques.
- Un nœud n’apparaît pas dans la palette
Vérifier l’opcode, le décorateur
@register_node, le nom du fichier dansPyqtSimulator/nodeset les erreurs d’import au démarrage.- Un résultat ne se met pas à jour
Vérifier que les champs sont connectés à
onInputChanged. AvecESMNode, cette connexion est automatique pourFIELDSetCHOICES.- Une connexion est refusée
Le moteur empêche de relier deux entrées, deux sorties ou un nœud à lui-même. Repartir de la sortie du nœud amont vers l’entrée du nœud aval.
- Un plot manque dans ReadTheDocs
Vérifier que la figure est générée dans
docs/source/imagesavant le build et que le document référence exactement le bon nom de fichier.
Checklist pour finaliser un exemple
Avant de considérer une page comme complète :
Le scénario est compréhensible sans lire le code source.
Les nœuds et connexions sont schématisés.
Les paramètres d’entrée sont listés avec unités.
Les résultats sont affichés dans une table lisible.
Les plots existants du modèle sont affichés.
Les limites de validité sont indiquées.
Le code est reproductible depuis un environnement propre.
Le build Sphinx passe sans erreur liée à la page.