Navigation : Index # CC3 : SmartGrid - Ordonnancement de la production energetique sous incertitude
Étude de cas interdisciplinaire combinant programmation par contraintes (OR-Tools CP-SAT), inference probabiliste (modèle bayesien), optimisation multi-objectif et un jumeau numérique de reseau electrique.
Contexte metier
Un opérateur de reseau electrique doit, pour chaque heure, decider quelles centrales activer et a quel niveau de production (le unit commitment / dispatch) afin de satisfaire la demande tout en minimisant le cout economique et les emissions de CO2. Ce problème est rendu difficile par :
l’incertitude sur la production renouvelable (eolien, solaire) et sur la demande ;
les contraintes dures : capacites min/max des centrales, temps de montee/descente, reserve tournante (securite n-1) ;
les objectifs multiples conflictuels : cout, emissions, fiabilite.
Une seule technique ne suffit pas : un solveur déterministe ignore l’incertitude, un modèle probabiliste seul ne respecte pas les contraintes physiques. Cette étude de cas materialise leur composition ordonnee : filtrer les dispatches impossibles (contraintes), modeliser l’aleatoire (incertitude), puis optimiser (multi-objectif).
Architecture en 4 couches
Couche
Rôle
Technique
Partie
Contraintes dures
Filtrer les dispatches impossibles
OR-Tools CP-SAT
Partie 1
Incertitude
Modeliser l’aleatoire renouvelable
Modèle bayesien
Partie 2
Optimisation
Choisir le meilleur compromis
Multi-objectif pondere
Partie 3
Decision
Synthese + comparaison
Workflow + scoring
Partie 4
Ce squelette est une fondation a completer : le jumeau numérique (couche 0) est operationnel ; les implementations des 4 couches sont les exercices a realiser — le corrige (../solution/) les exécute de bout en bout, outputs a l’appui.
0. Installation et jumeau numérique
Le jumeau numérique represente un reseau electrique : un ensemble de centrales (avec cout, capacites, facteur d’emission) et une demande horaire a satisfaire, avec une production renouvelable stochastique.
# Installation des dependances (solveurs des Parties 1-4 ; a completer par l etudiant)# %pip install ortools numpy scipy # decommenter pour execution completefrom dataclasses import dataclass, fieldfrom typing import List, Dictimport numpy as np@dataclassclass PowerPlant:"""Centrale de production electrique.""" name: str pmin: float# puissance minimale stable (MW) pmax: float# puissance maximale (MW) cost_per_mw: float# cout variable (EUR/MWh) co2_per_mw: float# emission (kg/MWh) is_renewable: bool=False@dataclassclass PowerNetwork:"""Jumeau numerique d'un reseau electrique horaire.""" plants: List[PowerPlant] demand_mw: List[float] # demande par heure (MW) renewable_forecast_mean: List[float] # production renouvelable moyenne attendue (MW) renewable_forecast_std: List[float] # incertitude (ecart-type, MW)def total_capacity(self) ->float:returnsum(p.pmax for p inself.plants)def net_demand(self, hour: int) ->float:"""Demande a couvrir par les centrales pilotables apres renouvelable."""returnmax(0.0, self.demand_mw[hour] -self.renewable_forecast_mean[hour])def demo_network() -> PowerNetwork:"""Reseau de demonstration : 3 centrales pilotables + renouvelable sur 6 heures.""" plants = [ PowerPlant('Charbon', 50, 400, cost_per_mw=30, co2_per_mw=900), PowerPlant('Gaz', 20, 250, cost_per_mw=60, co2_per_mw=400), PowerPlant('Hydro', 0, 150, cost_per_mw=10, co2_per_mw=0, is_renewable=False), ]return PowerNetwork( plants=plants, demand_mw=[500, 520, 480, 540, 600, 580], renewable_forecast_mean=[80, 60, 40, 50, 120, 150], renewable_forecast_std=[15, 12, 10, 12, 25, 30], )net = demo_network()print(f'Reseau : {len(net.plants)} centrales, capacite totale {net.total_capacity()} MW')for h inrange(len(net.demand_mw)):print(f' H{h}: demande {net.demand_mw[h]} MW, renouvelable {net.renewable_forecast_mean[h]} 'f'+/- {net.renewable_forecast_std[h]}, demande nette {net.net_demand(h):.1f} MW')
La sortie de cette cellule de démonstration présente la configuration complète du réseau électrique numérique utilisé comme cas d’étude. Le message “Reseau : 3 centrales, capacite totale 800 MW” indique que le jumeau numérique comprend trois centrales de production : Charbon (400 MW, coût 30 EUR/MWh, 900 kg CO2/MWh), Gaz (250 MW, coût 60 EUR/MWh, 400 kg CO2/MWh) et Hydro (150 MW, coût 10 EUR/MWh, 0 kg CO2/MWh). La capacité totale de 800 MW représente la puissance maximale disponible pour répondre à la demande horaire. Les lignes suivantes détaillent, pour chacune des 6 heures de la période d’étude, la demande brute en mégawatts, la production renouvelable prévue avec son incertitude (moyenne et écart-type), et la demande nette à couvrir par les centrales pilotables. Par exemple, à l’heure 0, une demande de 500 MW est partiellement couverte par 80 MW de production renouvelable (avec une incertitude de ±15 MW), laissant une demande nette de 420 MW à satisfaire par les centrales thermiques et hydrauliques.
Partie 1 : Le Dispatcher sous Contraintes (OR-Tools CP-SAT)
Théorie : le unit commitment est un problème NP-difficile. On modelise, pour chaque heure et chaque centrale pilotable, une variable binaire (activee) et une variable continue (niveau de production), soumises aux contraintes :
somme des productions = demande nette (equilibre offre/demande) ;
pmin <= production <= pmax quand la centrale est activee ;
reserve tournante : capacite excédentaire disponible >= marge de securite.
L’objectif primaire : minimiser le cout total.
# Partie 1 : modele CP-SAT du dispatch (unit commitment)# TODO etudiant : implementer solve_dispatch_cp avec ortools.sat.python.cp_model.# Pour chaque heure et centrale pilotable : binaire `on` + entier `p`.# Contraintes : equilibre offre/demande nette + bornes pmin <= p <= pmax.# Objectif : minimiser le cout total.def solve_dispatch_cp(network, cost_weights=None):"""Resout le unit commitment par programmation par contraintes (CP-SAT).""" result =None# TODO etudiantreturn resultdispatch = solve_dispatch_cp(net)print('Dispatch CP-SAT :', dispatch)
Dispatch CP-SAT : None
Optimisation multi-objectif
Le problème de dispatch électrique abordé dans ce notebook se caractérise par sa nature multi-objectif, où plusieurs critères doivent être optimisés simultanément. Le premier critère, économique, vise à minimiser le coût total de production en privilégiant les centrales les moins chères (Hydro à 10 EUR/MWh, Charbon à 30 EUR/MWh, Gaz à 60 EUR/MWh). Le deuxième critère, environnemental, cherche à réduire l’empreinte carbone en limitant l’utilisation des centrales les plus polluantes (Charbon à 900 kg CO2/MWh, Gaz à 400 kg CO2/MWh). Le troisième critère, la gestion du risque, prend en compte l’incertitude associée à la production renouvelable, modélisée par des distributions de probabilité avec écart-type. Le réseau de démonstration illustré précédemment montre comment ces différents objectifs peuvent entrer en conflit : la centrale à charbon, bien que la moins chère, est également la plus polluante, tandis que l’hydroélectricité, propre et bon marché, a une capacité limitée. La solution optimale doit donc trouver un compromis entre ces différentes dimensions.
Exercice 1 : Reserve tournante (securite n-1)
Ajoutez au modèle CP-SAT une contrainte de reserve tournante : a chaque heure, la somme des capacites disponibles (non utilisees) des centrales activees doit couvrir la perte de la plus grande centrale en service (critere n-1).
Indice : pour chaque heure, la reserve = sum(pmax_i - prod_i pour i active) doit etre >= max(pmax_i pour i active).
# Exercice 1 : contrainte de reserve tournante n-1def solve_dispatch_with_spinning_reserve(network: PowerNetwork):"""Dispatch CP-SAT avec reserve tournante n-1.""" result =None# TODO etudiant : etendre solve_dispatch_cp avec la reserve n-1return result
Partie 2 : Le Previsionniste Probabiliste (modèle bayesien)
Théorie : la production renouvelable est aleatoire. On modelise l’ecart demande - renouvelable comme une variable aleatoire et on infere sa distribution, pour quantifier le risque de defaillance (probabilite que la demande nette depasse la capacite pilotable disponible).
# Partie 2 : modele bayesien de l'incertitude renouvelable# TODO etudiant : P(demande nette reelle > capacite pilotable).# Modele l'ecart offre/demande comme une gaussienne et utilise sa survivor function.from math import erfc, sqrtdef failure_risk(network, hour):"""Probabilite que la demande nette (aleatoire) depasse la capacite pilotable.""" risk =None# TODO etudiant : calculer via la survivor function d'une gaussiennereturn riskprint('Risque de defaillance (a completer par l'+'etudiant) :')for h inrange(len(net.demand_mw)):print(f' H{h}: risque = {failure_risk(net, h)}')
Lecture du résultat — risque de défaillance (squelette étudiant)
Les six valeurs None affichées ci-dessus sont attendues : la fonction failure_risk renvoie encore le marqueur None tant que son calcul n’est pas complété. Elles ne représentent ni un risque nul ni une erreur d’exécution. Après avoir implémenté la probabilité de dépassement de la capacité pilotable, réexécutez la Partie 2 avant de comparer les heures dans l’exercice suivant.
Exercice 2 : Sensibilite au prior sur la variabilite eolienne
Analysez comment le risque de defaillance (Partie 2) evolue quand on modifie l’incertitude du renouvelable (multipliez renewable_forecast_std par 0.5, 1.0, 2.0). Quelle heure devient la plus risqueuse ? Concluez sur la robustesse du dispatch determine en Partie 1.
# Exercice 2 : analyse de sensibilite au prior d'incertitudedef sensitivity_to_renewable_std(network: PowerNetwork, factors=(0.5, 1.0, 2.0)):"""Retourne le risque max par heure pour chaque facteur d'incertitude.""" result =None# TODO etudiant : boucler sur les facteurs, retourner {factor: max_risk}return result
Architecture en quatre couches
L’architecture logicielle proposée pour résoudre le problème de SmartGrid repose sur une décomposition en quatre couches fonctionnelles distinctes. La couche 1, dédiée au dispatch sous contraintes, utilise l’outil OR-Tools CP-SAT pour effectuer un unit commitment optimal en tenant compte des contraintes physiques et techniques du réseau. La couche 2, le prévisionniste probabiliste, implémente un modèle bayésien pour estimer l’incertitude associée à la production renouvelable, permettant ainsi une prise de décision éclairée face à la variabilité des énergies vertes. La couche 3, l’optimiseur multi-objectif, aggrège les différents critères (coût, CO2, risque) en un score unique permettant de comparer les stratégies de dispatch entre elles. Enfin, la couche 4, l’analyse comparative, évalue les différentes stratégies en fonction de leur performance sur l’ensemble des critères, fournissant ainsi une base objective pour la prise de décision finale. Cette séparation des préoccupations permet une modularité accrue et facilite la maintenance et l’évolution du système.
Partie 3 : L’Optimiseur Multi-Objectif
Théorie : on veut minimiser simultanement le cout economique, les emissions CO2 et le risque de defaillance. Ces objectifs sont conflictuels (le charbon est bon marche mais très emissif). On construit un score pondere S = a*cout + b*co2 + c*risque et on cherche le dispatch minimisant S, en explorant le front de Pareto.
# Partie 3 : score multi-objectif (cout + CO2 + risque)# TODO etudiant : normaliser chaque objectif puis combiner par somme ponderee.def dispatch_metrics(dispatch, network):"""Calcule cout total, CO2 total et risque max d'un dispatch."""if dispatch isNone:return {'cost': float('inf'), 'co2': float('inf'), 'max_risk': 1.0} metrics =None# TODO etudiant : boucler sur heures + plantsreturn metricsdef multi_objective_score(dispatch, network, weights=(1.0, 1.0, 1.0), norms=None):"""Score = w_c*cout_norm + w_co2*co2_norm + w_r*risque_norm.""" score =None# TODO etudiantreturn scoreprint('Score multi-objectif :', multi_objective_score(dispatch, net))
Score multi-objectif : None
Exercice 3 : Ajouter un troisieme objectif (equite territoriale)
Ajoutez un troisieme objectif : equite territoriale (eviter qu’une même region subisse toutes les centrales les plus polluantes). Supposons que chaque centrale a un attribut region. Mesurez la concentration regionale de la pollution et ajoutez-la au score.
Analyse comparative et prise de décision
La dernière partie du notebook effectue une analyse comparative des différentes stratégies de dispatch en évaluant leur performance selon les trois critères principaux : coût économique, émission de CO2, et niveau de risque lié à l’incertitude renouvelable. Cette évaluation multi-critères permet de mettre en évidence les compromis inhérents à chaque approche : une stratégie minimisant le coût peut engendrer des émissions de CO2 élevées, tandis qu’une stratégie environnementalement optimale peut être plus coûteuse ou plus risquée. L’analyse comparative fournit aux décideurs une vision globale des conséquences de chaque choix, leur permettant de sélectionner la stratégie la plus adaptée aux priorités du moment (par exemple, minimiser les coûts en période de faible demande, ou réduire l’empreinte carbone lorsque les ressources renouvelables sont abondantes). Cette approche systémique illustre comment l’intelligence artificielle et les méthodes d’optimisation peuvent supporter des décisions complexes dans le domaine de la gestion des réseaux électriques.
# Exercice 3 : objectif d'equite territorialedef territorial_equity_score(dispatch, network: PowerNetwork) ->float:"""Mesure de concentration de la pollution par region (0 = equitable).""" score =None# TODO etudiant : mesurer la concentration (ex: variance/entropy regionale des co2)return score
Partie 4 : Decision finale et analyse comparative
Synthese : on compare les stratégies (CP-SAT pur, multi-objectif weighted-sum, front de Pareto) sur les 3 axes cout/CO2/fiabilite + l’equite territoriale. Le tableau comparatif et le graphique radar seront produits une fois les Parties 1-3 executees.
# Partie 4 : analyse comparative des strategies de dispatch# TODO etudiant : comparer 3 strategies (min cout / min CO2 / compromis).def comparative_analysis(network):"""Compare 3 strategies CP-SAT sur cout / CO2 / risque.""" analysis =None# TODO etudiant : re-solve 3x, normaliser, scorerreturn analysisprint('Analyse comparative :', comparative_analysis(net))
Analyse comparative : None
Conclusion
Cette étude de cas illustre la composition ordonnee des paradigmes IA sur un problème metier reel (transition energetique) : on filtre les dispatches impossibles (CP-SAT) avant de modeliser l’incertitude (bayesien) avant d’optimiser (multi-objectif). Inverser l’ordre produit un système soit trop rigide (contraintes ignorent l’aleatoire), soit trop flou (decision sans contraintes physiques).
Etat du squelette : jumeau numérique operationnel (couche 0), 4 couches de solveurs modelisees en stub. Implementations + exécution + analyse comparative : a completer par l’etudiant — le corrige (../solution/) montre la version exécutée de bout en bout.