operations_research/OR_HTML_04/supplychain.html
dschlueter b6de2802fc Glossar und Literatur trennen, Menue um Glossar und ZIP-Download ergaenzen
94_Anhang_Glossar_und_Literatur.md enthielt zwei verschiedene Nachschlagewerke
in einer Datei. Jetzt sind es zwei Anhaenge: E = Glossar (92 Eintraege),
F = Literaturverzeichnis (6 Kategorien). Aus 5 Anhaengen werden 6, aus 36
Kapiteldateien 37.

Die Teilung war billig: Die Datei trug bereits zwei eigenstaendige
Ueberschriften mit nichts als einem --- dazwischen, und im ganzen Buch gab es
genau einen {ref:anhang:glossar-literatur} - die Weiter-mit-Zeile im
Spickzettel. Geprueft: keine Inhaltszeile verloren, alle 92 Glossareintraege
auf der neuen Seite, Indexmarken unveraendert bei 328.

Das Seitenleisten-Menue bekommt zwei Eintraege:

  Beispielprogramme
  Notebooks
    Download Notebooks als ZIP     <- neu, eingerueckt
  Glossar                          <- neu
  Stichwortverzeichnis
  Gesamtdokument (eine Seite)
  Download als PDF

Der ZIP-Link benutzt dieselbe Konstante wie baue_notebooks_seite() beim
Schreiben des Archivs, damit Link und Datei nicht auseinanderlaufen. Das
Glossar erscheint absichtlich doppelt: hier als Abkuerzung neben dem
Stichwortverzeichnis, und unten in der Gruppe "Anhaenge", weil es ein Anhang
ist.

Die verwaiste anhang-glossar-literatur.html von Hand entfernt - der Build
raeumt alte Seiten nicht ab.

Nebenbefund, in PROGRESS.md festgehalten: OR_HTML_04/assets/site.css ist eine
von Hand gepflegte Quelle, die im als "generiert" beschriebenen Verzeichnis
liegt. Der Build schreibt sie nie. Dasselbe gilt fuer site.js, icons.svg,
highlight.css und plotly.min.js.

--check: 5 Teile, 23 Kapitel, 6 Anhaenge, 296 Abschnitte, 825 Querverweise,
328 Indexmarken, 37 Dateien, 28.544 Zeilen, 305 Hauptueberschriften, keine
Warnung. PDF unveraendert 759 Seiten.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 15:48:57 +02:00

904 lines
120 KiB
HTML
Generated
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Kapitel 17: Supply-Chain und Energieeinsatz unter Unsicherheit · Optimierte Entscheidungsfindung mit Python</title>
<script>
(function () {
try {
var t = localStorage.getItem("or-theme");
if (t) document.documentElement.setAttribute("data-theme", t);
} catch (e) {}
})();
</script>
<link rel="stylesheet" href="assets/highlight.css" />
<link rel="stylesheet" href="katex/katex.min.css" />
<script defer="" src="katex/katex.min.js"></script>
<script>document.addEventListener("DOMContentLoaded", function () {
var mathElements = document.getElementsByClassName("math");
var macros = [];
for (var i = 0; i < mathElements.length; i++) {
var texText = mathElements[i].firstChild;
if (mathElements[i].tagName == "SPAN") {
katex.render(texText.data, mathElements[i], {
displayMode: mathElements[i].classList.contains('display'),
throwOnError: false,
macros: macros,
fleqn: false
});
}}
// Der Browser springt zu einem #anker in der URL schon beim ersten Rendern
// an, BEVOR die KaTeX-Formeln oben im Text ihre finale Hoehe bekommen -
// durch den Reflow landet der Anker danach zu weit unten. Nach dem
// Formel-Rendering hier erneut zum Anker springen, das behebt es.
if (location.hash) {
var ziel = document.getElementById(decodeURIComponent(location.hash.slice(1)));
if (ziel) ziel.scrollIntoView({behavior: "instant", block: "start"});
}
});
</script>
<link rel="stylesheet" href="assets/site.css" />
</head>
<body>
<svg style="display:none" aria-hidden="true"><symbol id="icon-menu" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/>
</symbol>
<symbol id="icon-search" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.2" y2="16.2"/>
</symbol>
<symbol id="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<circle cx="12" cy="12" r="4.5"/>
<line x1="12" y1="1.5" x2="12" y2="4"/><line x1="12" y1="20" x2="12" y2="22.5"/>
<line x1="1.5" y1="12" x2="4" y2="12"/><line x1="20" y1="12" x2="22.5" y2="12"/>
<line x1="4.5" y1="4.5" x2="6.2" y2="6.2"/><line x1="17.8" y1="17.8" x2="19.5" y2="19.5"/>
<line x1="19.5" y1="4.5" x2="17.8" y2="6.2"/><line x1="6.2" y1="17.8" x2="4.5" y2="19.5"/>
</symbol>
<symbol id="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M20 14.5A8.5 8.5 0 1 1 9.5 4a6.8 6.8 0 0 0 10.5 10.5z"/>
</symbol>
<symbol id="icon-chevron-left" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="15 4 7 12 15 20"/>
</symbol>
<symbol id="icon-chevron-right" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="9 4 17 12 9 20"/>
</symbol>
<symbol id="icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="4 13 9.5 18.5 20 6"/>
</symbol>
<symbol id="icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 13.5V19a1.5 1.5 0 0 1-1.5 1.5H5A1.5 1.5 0 0 1 3.5 19V7A1.5 1.5 0 0 1 5 5.5h5.5"/>
<polyline points="14.5 3.5 20.5 3.5 20.5 9.5"/><line x1="11" y1="13" x2="20" y2="4"/>
</symbol>
<symbol id="icon-book" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 5.5A2 2 0 0 1 6 4h6v16H6a2 2 0 0 0-2 1.5z"/>
<path d="M20 5.5A2 2 0 0 0 18 4h-6v16h6a2 2 0 0 1 2 1.5z"/>
</symbol>
<symbol id="icon-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
</symbol>
<symbol id="icon-download" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 3v12"/><polyline points="7 10 12 15 17 10"/><path d="M4 19.5h16"/>
</symbol></svg>
<header class="site-header">
<button type="button" class="icon-btn" id="sidebar-toggle" aria-label="Menü öffnen"><svg class="icon" aria-hidden="true"><use href="#icon-menu"></use></svg></button>
<a class="brand" href="index.html"><svg class="icon" aria-hidden="true"><use href="#icon-book"></use></svg> <span>Optimierte Entscheidungsfindung mit Python</span></a>
<div class="site-search">
<input id="suche-eingabe" type="search" placeholder="Suchen …" aria-label="Suche" autocomplete="off" />
<svg class="icon such-icon" aria-hidden="true"><use href="#icon-search"></use></svg>
<div id="suche-ergebnisse" class="suche-ergebnisse" hidden></div>
</div>
<button type="button" class="icon-btn" id="theme-toggle" aria-label="Darstellung umschalten">
<svg class="icon icon-sun" aria-hidden="true"><use href="#icon-sun"></use></svg><svg class="icon icon-moon" aria-hidden="true"><use href="#icon-moon"></use></svg>
</button>
</header>
<div class="site-body">
<div class="sidebar-overlay" id="sidebar-overlay" hidden></div>
<nav class="sidebar" id="sidebar" aria-label="Kapitelnavigation"><div class="sidebar-inhalt"><details class="sidebar-gruppe"><summary>Einstieg</summary><ul><li data-kapitel="vorwort.html"><a href="vorwort.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Vorwort & Lesehilfe</span></a></li><li data-kapitel="notation.html"><a href="notation.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Notation & Abkürzungen</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Teil I: Grundlagen des Operations Research</summary><ul><li data-kapitel="einfuehrung.html"><a href="einfuehrung.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 1: Einführung in Operations Research — Vom Ursprung zur mathematischen Entscheidungsfindung</span></a></li><li data-kapitel="fundament.html"><a href="fundament.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 2: Das mathematische Fundament — Vektoren, Matrizen, Konvexität</span></a></li><li data-kapitel="oekosystem.html"><a href="oekosystem.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 3: Das Python-Ökosystem für OR — Solver, Bindings und Modellierungsschichten</span></a></li><li data-kapitel="modellierung.html"><a href="modellierung.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 4: Vom Management-Wunsch zum Modell</span></a></li><li data-kapitel="synthese-grundlagen.html"><a href="synthese-grundlagen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Synthese Teil I</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Teil II: Die Kernverfahren der deterministischen Optimierung</summary><ul><li data-kapitel="lp.html"><a href="lp.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 5: Lineare Programmierung — Simplex, Dualität und Schattenpreise</span></a></li><li data-kapitel="milp.html"><a href="milp.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 6: Gemischt-ganzzahlige Optimierung — Diskrete Entscheidungen und Branch-and-Bound</span></a></li><li data-kapitel="cpsat.html"><a href="cpsat.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 7: Constraint Programming mit CP-SAT — Logik, Scheduling und Zuweisung</span></a></li><li data-kapitel="graphen.html"><a href="graphen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 8: Graphen, Flüsse und Touren — Min-Cost-Flow, Matching und VRP</span></a></li><li data-kapitel="metaheuristiken.html"><a href="metaheuristiken.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 9: Metaheuristiken — wenn der exakte Solver aussteigt</span></a></li><li data-kapitel="dekomposition.html"><a href="dekomposition.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 10: Spaltengenerierung — das Modell umbauen statt die Lösung raten</span></a></li><li data-kapitel="synthese-kernverfahren.html"><a href="synthese-kernverfahren.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Synthese Teil II</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Teil III: Nichtlinearität, Unsicherheit und mehrperiodige Dynamik</summary><ul><li data-kapitel="qp-nlp.html"><a href="qp-nlp.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 11: Quadratische und nichtlineare Optimierung — KKT, Lagrange, Konvexität</span></a></li><li data-kapitel="unsicherheit.html"><a href="unsicherheit.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 12: Optimierung unter Unsicherheit — Monte-Carlo, Stochastik, Robustheit</span></a></li><li data-kapitel="dynamische-programmierung.html"><a href="dynamische-programmierung.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 13: Dynamische Programmierung — Die Bellman-Gleichung und Order-Execution</span></a></li><li data-kapitel="mehrziel.html"><a href="mehrziel.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 14: Mehrere Ziele — Pareto-Fronten statt Gewichte</span></a></li><li data-kapitel="prognose.html"><a href="prognose.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 15: Predict-then-Optimize — die bessere Prognose, die schlechtere Entscheidung</span></a></li><li data-kapitel="synthese-nichtlinear.html"><a href="synthese-nichtlinear.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Synthese Teil III</span></a></li></ul></details><details class="sidebar-gruppe" open><summary>Teil IV: Anwendungen — Energiewirtschaft und Finanzmärkte</summary><ul><li data-kapitel="bruecke.html"><a href="bruecke.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 16: Die Strukturbrücke — dieselbe Mathematik, zwei Welten</span></a></li><li data-kapitel="supplychain.html" class="aktiv"><a href="supplychain.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 17: Supply-Chain und Energieeinsatz unter Unsicherheit</span></a></li><li data-kapitel="finanzdaten.html"><a href="finanzdaten.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 18: Finanzdaten-Modellierung — Renditen, Kovarianz und Shrinkage</span></a></li><li data-kapitel="markowitz.html"><a href="markowitz.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 19: Die moderne Portfoliotheorie nach Markowitz</span></a></li><li data-kapitel="cvar.html"><a href="cvar.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 20: Tail-Risiko, CVaR und Transaktionskosten</span></a></li><li data-kapitel="handelsmaschine.html"><a href="handelsmaschine.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 21: Die vollständige quantitative Handelsmaschine</span></a></li><li data-kapitel="synthese-anwendungen.html"><a href="synthese-anwendungen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Synthese Teil IV</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Teil V: Praxis</summary><ul><li data-kapitel="praxisfallen.html"><a href="praxisfallen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 22: Praxisfallen und der Weg zum produktiven Einsatz</span></a></li><li data-kapitel="testing.html"><a href="testing.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 23: Testen, Messen, Ausliefern</span></a></li><li data-kapitel="synthese-praxis.html"><a href="synthese-praxis.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Synthese Teil V</span></a></li><li data-kapitel="projektwerkstatt.html"><a href="projektwerkstatt.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Projektwerkstatt</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Anhänge</summary><ul><li data-kapitel="anhang-loesungen.html"><a href="anhang-loesungen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang A: Lösungen zu allen Übungsaufgaben</span></a></li><li data-kapitel="anhang-modellierungsmuster.html"><a href="anhang-modellierungsmuster.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang B: Katalog der Modellierungsmuster</span></a></li><li data-kapitel="anhang-fehlerdiagnose.html"><a href="anhang-fehlerdiagnose.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang C: Fehlerdiagnose-Handbuch</span></a></li><li data-kapitel="anhang-spickzettel.html"><a href="anhang-spickzettel.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang D: Spickzettel der Solver</span></a></li><li data-kapitel="anhang-glossar.html"><a href="anhang-glossar.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang E: Glossar</span></a></li><li data-kapitel="anhang-literatur.html"><a href="anhang-literatur.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang F: Literaturverzeichnis</span></a></li></ul></details><ul class="sidebar-extra"><li><a href="programme.html"><svg class="icon" aria-hidden="true"><use href="#icon-book"></use></svg> Beispielprogramme</a></li><li><a href="notebooks.html"><svg class="icon" aria-hidden="true"><use href="#icon-book"></use></svg> Notebooks</a></li><li class="sidebar-unterpunkt"><a href="Notebooks_04.zip" download><svg class="icon" aria-hidden="true"><use href="#icon-download"></use></svg> Download Notebooks als ZIP</a></li><li><a href="anhang-glossar.html"><svg class="icon" aria-hidden="true"><use href="#icon-book"></use></svg> Glossar</a></li><li><a href="stichwortverzeichnis.html"><svg class="icon" aria-hidden="true"><use href="#icon-search"></use></svg> Stichwortverzeichnis</a></li><li><a href="gesamtdokument.html"><svg class="icon" aria-hidden="true"><use href="#icon-external-link"></use></svg> Gesamtdokument (eine Seite)</a></li><li><a href="Operations_Research_mit_Python_Version_04.pdf" download><svg class="icon" aria-hidden="true"><use href="#icon-download"></use></svg> Download als PDF</a></li></ul></div></nav>
<main class="content">
<nav class="breadcrumb" aria-label="Breadcrumb"><a href="index.html">Start</a> <span>Teil IV</span> <span>Kapitel 17: Supply-Chain und Energieeinsatz unter Unsicherheit</span></nav>
<nav class="prev-next"><a class="prev-next-knopf prev-next-prev" href="bruecke.html"><svg class="icon" aria-hidden="true"><use href="#icon-chevron-left"></use></svg><span><small>Zurück</small>Kapitel 16: Die Strukturbrücke — dieselbe Mathematik, zwei Welten</span></a><a class="prev-next-knopf prev-next-next" href="finanzdaten.html"><span><small>Weiter</small>Kapitel 18: Finanzdaten-Modellierung — Renditen, Kovarianz und Shrinkage</span><svg class="icon" aria-hidden="true"><use href="#icon-chevron-right"></use></svg></a></nav>
<article>
<h1 id="kap-supplychain">Kapitel 17: Supply-Chain und Energieeinsatz unter Unsicherheit</h1>
<div class="card card-blick">
<blockquote>
<p><strong>📌 Kapitel auf einen Blick</strong></p>
<p><strong>Worum geht es?</strong> Um einen zusammenhängenden Industriefall, der die Werkzeuge aus Teil II und III zusammenführt: gemischt-ganzzahlige Entscheidungen, Szenarien, Risikomaße — an der Kraftwerkseinsatzplanung, der klassischen Aufgabe der Energiewirtschaft.</p>
<p><strong>Voraussetzungen:</strong> <a href="milp.html#kap-milp">Kapitel 6</a>, <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a> (zweistufige stochastische Programmierung) und <a href="cvar.html#kap-cvar">Kapitel 20</a>.</p>
<p><strong>Danach können Sie:</strong> ein Modell aufsetzen, in dem die <strong>erste Stufe ganzzahlig</strong> ist und vor dem Zufall feststeht; erklären, warum eine Planung auf den Erwartungswert systematisch zu knapp ausfällt; und den Preis einer Versorgungssicherheitsvorgabe in Euro je vermiedener Megawattstunde ausweisen.</p>
<p><strong>Zeitbedarf:</strong> ca. 4 Stunden.</p>
<p><strong>Programme:</strong><br />
<code>Kraftwerkseinsatz.py</code></p>
<p><strong>Notebook:</strong> <a href="Notebooks_04/supplychain.ipynb">supplychain.ipynb</a> — herunterladen und in Jupyter öffnen, in Colab hochladen oder mit dem Kurs-Image starten</p>
</blockquote>
</div>
<hr />
<h2 id="sec:supplychain-schnellstart">17.1 In 5 Minuten gelöst</h2>
<div class="card card-schnellstart">
<blockquote>
<p><strong>🚀 In 5 Minuten gelöst: Warum „billigstes Kraftwerk zuerst” falsch ist</strong></p>
<p>Zwei Kraftwerke können 120 MW liefern. Der Kernblock produziert für 22 €/MWh, die Gasturbine für 105 € — fünfmal so teuer. Die Merit-Order-Regel sagt: Kernblock.</p>
<p>Sie übersieht die Anfahrkosten: 40 000 € gegen 1 500 €.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Zwei Kraftwerke, die 120 MW decken sollen - aber wie lange?</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="co"># Grenzkosten Anfahrkosten</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>kernblock <span class="op">=</span> <span class="bu">dict</span>(name<span class="op">=</span><span class="st">&quot;Kernblock&quot;</span>, grenz<span class="op">=</span><span class="dv">22</span>, anfahrt<span class="op">=</span><span class="dv">40_000</span>)</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>gasturbine <span class="op">=</span> <span class="bu">dict</span>(name<span class="op">=</span><span class="st">&quot;Gasturbine&quot;</span>, grenz<span class="op">=</span><span class="dv">105</span>, anfahrt<span class="op">=</span><span class="dv">1_500</span>)</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>LEISTUNG <span class="op">=</span> <span class="dv">120</span> <span class="co"># MW, die gebraucht werden</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>kosten <span class="op">=</span> <span class="kw">lambda</span> kw, stunden: kw[<span class="st">&quot;anfahrt&quot;</span>] <span class="op">+</span> kw[<span class="st">&quot;grenz&quot;</span>] <span class="op">*</span> LEISTUNG <span class="op">*</span> stunden</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f&quot;</span><span class="sc">{</span><span class="st">&#39;Dauer&#39;</span><span class="sc">:&gt;7}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;Kernblock&#39;</span><span class="sc">:&gt;12}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;Gasturbine&#39;</span><span class="sc">:&gt;12}</span><span class="ss"> guenstiger&quot;</span>)</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> stunden <span class="kw">in</span> (<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span>, <span class="dv">5</span>, <span class="dv">6</span>, <span class="dv">8</span>):</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a> k, g <span class="op">=</span> kosten(kernblock, stunden), kosten(gasturbine, stunden)</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;</span><span class="sc">{</span>stunden<span class="sc">:&gt;5}</span><span class="ss"> h </span><span class="sc">{</span>k<span class="sc">:&gt;12,.0f}</span><span class="ss"> </span><span class="sc">{</span>g<span class="sc">:&gt;12,.0f}</span><span class="ss"> &quot;</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;</span><span class="sc">{</span>kernblock[<span class="st">&#39;name&#39;</span>] <span class="cf">if</span> k <span class="op">&lt;</span> g <span class="cf">else</span> gasturbine[<span class="st">&#39;name&#39;</span>]<span class="sc">}</span><span class="ss">&quot;</span>)</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>wechsel <span class="op">=</span> (kernblock[<span class="st">&quot;anfahrt&quot;</span>] <span class="op">-</span> gasturbine[<span class="st">&quot;anfahrt&quot;</span>]) <span class="op">/</span> (</span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a> (gasturbine[<span class="st">&quot;grenz&quot;</span>] <span class="op">-</span> kernblock[<span class="st">&quot;grenz&quot;</span>]) <span class="op">*</span> LEISTUNG)</span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f&quot;</span><span class="ch">\n</span><span class="ss">Umschlagpunkt: </span><span class="sc">{</span>wechsel<span class="sc">:.1f}</span><span class="ss"> Stunden&quot;</span>)</span></code></pre></div>
<p><strong>Ausgabe:</strong></p>
<pre><code> Dauer Kernblock Gasturbine guenstiger
1 h 42,640 14,100 Gasturbine
2 h 45,280 26,700 Gasturbine
3 h 47,920 39,300 Gasturbine
4 h 50,560 51,900 Kernblock
5 h 53,200 64,500 Kernblock
6 h 55,840 77,100 Kernblock
8 h 61,120 102,300 Kernblock
Umschlagpunkt: 3.9 Stunden</code></pre>
</blockquote>
</div>
<p><strong>Und jetzt der Punkt.</strong> Bis knapp vier Stunden ist die <em>fünfmal teurere</em> Gasturbine die günstigere Wahl. Erst danach hat der Kernblock seine Anfahrkosten wieder eingespielt.</p>
<p>Die Merit-Order — Kraftwerke nach Grenzkosten sortieren und von unten auffüllen — ist damit nur für einen <strong>einzelnen</strong> Zeitpunkt richtig. Sobald ein Tag geplant wird, hängt jede Stunde an allen anderen: Ein Block, der um 8 Uhr angefahren wird, muss bis mindestens 16 Uhr laufen, und diese Entscheidung fällt am Vorabend.</p>
<blockquote>
<p><strong>🎯 Merksatz</strong> Anfahrkosten und Mindestlaufzeiten machen aus 24 unabhängigen Stundenentscheidungen <strong>ein</strong> Problem. Genau deshalb ist die Kraftwerkseinsatzplanung ein MILP und keine Sortierung.</p>
</blockquote>
<p><strong>Warum funktioniert das?</strong> Der Umschlagpunkt ist eine einfache Rechnung: Die Anfahrkostendifferenz (38 500 €) geteilt durch die Grenzkostendifferenz je Stunde (83 €/MWh × 120 MW = 9 960 €/h) ergibt 3,9 Stunden. Bei zwei Kraftwerken kann man das im Kopf ausrechnen — bei fünf Blöcken und 24 Stunden nicht mehr.</p>
<hr />
<h2 id="sec:supplychain-lernziele">17.2 Lernziele</h2>
<p>Nach diesem Kapitel können Sie …</p>
<ol type="1">
<li>… ein Unit-Commitment-Modell mit Anfahrkosten und Mindestlaufzeiten aufstellen.</li>
<li>… erklären, warum eine <strong>binäre erste Stufe</strong> das zweistufige Modell aus <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a> verschärft.</li>
<li>… zeigen, dass eine Planung auf den Erwartungswert nicht nur ungenau, sondern <strong>systematisch zu knapp</strong> ist.</li>
<li>… eine CVaR-Schranke auf eine physikalische Größe (nicht gedeckte Energie) legen.</li>
<li>… begründen, wann eine Risikoschranke etwas ändert — und wann sie überflüssig ist.</li>
</ol>
<hr />
<h2 id="sec:supplychain-aufgabe">17.3 Die Aufgabe</h2>
<p>Fünf Blöcke, 24 Stunden, eine Last zwischen 270 und 804 MW. Dazu Windeinspeisung, die niemand am Vorabend kennt.</p>
<table>
<colgroup>
<col style="width: 13%" />
<col style="width: 17%" />
<col style="width: 17%" />
<col style="width: 17%" />
<col style="width: 17%" />
<col style="width: 17%" />
</colgroup>
<thead>
<tr class="header">
<th>Block</th>
<th style="text-align: right;"><span class="math inline">P_{\min}</span></th>
<th style="text-align: right;"><span class="math inline">P_{\max}</span></th>
<th style="text-align: right;">Grenzkosten</th>
<th style="text-align: right;">Anfahrkosten</th>
<th style="text-align: right;">Mindestlaufzeit</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Kernblock</td>
<td style="text-align: right;">200</td>
<td style="text-align: right;">600</td>
<td style="text-align: right;">22 €/MWh</td>
<td style="text-align: right;">40 000 €</td>
<td style="text-align: right;">8 h</td>
</tr>
<tr class="even">
<td>Braunkohle</td>
<td style="text-align: right;">100</td>
<td style="text-align: right;">400</td>
<td style="text-align: right;">35 €/MWh</td>
<td style="text-align: right;">18 000 €</td>
<td style="text-align: right;">6 h</td>
</tr>
<tr class="odd">
<td>Steinkohle</td>
<td style="text-align: right;">80</td>
<td style="text-align: right;">300</td>
<td style="text-align: right;">48 €/MWh</td>
<td style="text-align: right;">12 000 €</td>
<td style="text-align: right;">4 h</td>
</tr>
<tr class="even">
<td>Gas GuD</td>
<td style="text-align: right;">50</td>
<td style="text-align: right;">250</td>
<td style="text-align: right;">72 €/MWh</td>
<td style="text-align: right;">6 000 €</td>
<td style="text-align: right;">2 h</td>
</tr>
<tr class="odd">
<td>Gasturbine</td>
<td style="text-align: right;">20</td>
<td style="text-align: right;">150</td>
<td style="text-align: right;">105 €/MWh</td>
<td style="text-align: right;">1 500 €</td>
<td style="text-align: right;">1 h</td>
</tr>
</tbody>
</table>
<p>Die Reihenfolge ist typisch: <strong>je billiger im Betrieb, desto träger und teurer im Anfahren.</strong> Das ist keine Willkür, sondern Physik — ein großer Dampfprozess braucht Stunden, bis er auf Temperatur ist.</p>
<h3 id="die-zeitstruktur-der-entscheidung">Die Zeitstruktur der Entscheidung</h3>
<p>Hier geht das Kapitel über <a href="unsicherheit.html#sec:unsicherheit-zweistufige-stochastische-programmierung">Abschnitt 12.5</a> hinaus:</p>
<table>
<colgroup>
<col style="width: 25%" />
<col style="width: 25%" />
<col style="width: 25%" />
<col style="width: 25%" />
</colgroup>
<thead>
<tr class="header">
<th>Stufe</th>
<th>Entscheidung</th>
<th>Typ</th>
<th>wann</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>1</strong></td>
<td>Welcher Block läuft in welcher Stunde?</td>
<td><strong>binär</strong>, für alle Szenarien gleich</td>
<td>am Vorabend, bevor der Wind bekannt ist</td>
</tr>
<tr class="even">
<td><strong>2</strong></td>
<td>Wie viel liefert jeder laufende Block?</td>
<td>kontinuierlich, je Szenario verschieden</td>
<td>am Tag selbst, laufend anpassbar</td>
</tr>
</tbody>
</table>
<p>Im Kapitel Unsicherheit war die erste Stufe kontinuierlich (Kapazität kaufen, Menge festlegen). Hier ist sie <strong>ganzzahlig</strong> — und das ändert die Sache grundlegend: Eine Kapazität lässt sich anteilig erhöhen, ein Kraftwerk nicht zu 30 % anfahren.</p>
<div class="card card-formel">
<blockquote>
<p><strong>🔤 Formel-Übersetzer: die Kopplung der beiden Stufen</strong></p>
<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<thead>
<tr class="header">
<th>Mathematik</th>
<th>Alltagssprache</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><span class="math inline">u_{k,t} \in \{0,1\}</span></td>
<td>„Läuft Block <span class="math inline">k</span> in Stunde <span class="math inline">t</span>?” — <strong>eine</strong> Antwort für alle Szenarien</td>
</tr>
<tr class="even">
<td><span class="math inline">p^s_{k,t} \ge P^{\min}_k \, u_{k,t}</span></td>
<td>„Ein laufender Block liefert mindestens seine Mindestleistung.”</td>
</tr>
<tr class="odd">
<td><span class="math inline">p^s_{k,t} \le P^{\max}_k \, u_{k,t}</span></td>
<td>„Ein stehender Block liefert gar nichts.” — dieselbe Big-M-Kopplung wie in <a href="milp.html#kap-milp">Kapitel 6</a></td>
</tr>
<tr class="even">
<td><span class="math inline">a_{k,t} \ge u_{k,t} - u_{k,t-1}</span></td>
<td>„Wer eben noch aus war und jetzt an ist, ist angefahren.”</td>
</tr>
<tr class="odd">
<td><span class="math inline">u_{k,\tau} \ge a_{k,t}</span> für <span class="math inline">\tau = t \dots t{+}L_k</span></td>
<td>Mindestlaufzeit: „Wer anfährt, bleibt <span class="math inline">L_k</span> Stunden am Netz.”</td>
</tr>
<tr class="even">
<td><span class="math inline">\sum_k p^s_{k,t} + w^s_t + y^s_t \ge D_t</span></td>
<td>„Erzeugung plus Wind plus Nichtdeckung deckt die Last.”</td>
</tr>
</tbody>
</table>
<p>Die beiden mittleren Zeilen sind der ganze Trick: Sie verbinden eine <strong>binäre</strong> Größe (<span class="math inline">u</span>) mit einer <strong>kontinuierlichen</strong> (<span class="math inline">p</span>) — und weil <span class="math inline">u</span> szenarioübergreifend gleich ist, die Szenarien untereinander.</p>
</blockquote>
</div>
<hr />
<h2 id="sec:supplychain-programm">17.4 Das Programm</h2>
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Kraftwerkseinsatz.py</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="co">&quot;&quot;&quot;</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="co">Kapitel Supply-Chain: Welche Bloecke laufen morgen? Und was, wenn kein Wind weht?</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="co">Die Kraftwerkseinsatzplanung (englisch Unit Commitment) ist die Aufgabe, an der</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="co">sich in der Energiewirtschaft alles entscheidet: Fuer jede Stunde des naechsten</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="co">Tages muss feststehen, welche Bloecke am Netz sind. Ein Kernblock braucht acht</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a><span class="co">Stunden Mindestlaufzeit und 40.000 Euro Anfahrkosten - wer ihn abschaltet, hat</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="co">ihn fuer den Rest des Tages verloren.</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a><span class="co">Das Besondere liegt in der Zeitstruktur, und es geht ueber das zweistufige</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a><span class="co">Modell aus dem Kapitel Unsicherheit hinaus:</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a><span class="co"> STUFE 1 Das AN/AUS je Block und Stunde. Binaer, und es steht am Vorabend</span></span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a><span class="co"> fest - bevor irgendjemand weiss, wie viel Wind morgen weht.</span></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a><span class="co"> STUFE 2 Die Fahrweise: wie viel jeder laufende Block liefert. Das darf</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a><span class="co"> sich stundenweise an die Wirklichkeit anpassen.</span></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a><span class="co">Die erste Stufe ist also GANZZAHLIG und szenariouebergreifend gleich, die</span></span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a><span class="co">zweite kontinuierlich und je Szenario verschieden. Genau diese Kombination</span></span>
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true" tabindex="-1"></a><span class="co">macht das Problem interessant - und sie ist der Grund, warum ein Plan, der auf</span></span>
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true" tabindex="-1"></a><span class="co">den Wind-Erwartungswert gerechnet wurde, in der Wirklichkeit teuer wird.</span></span>
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true" tabindex="-1"></a><span class="co">Das Programm zeigt drei Plaene auf denselben Daten:</span></span>
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-28"><a href="#cb3-28" aria-hidden="true" tabindex="-1"></a><span class="co"> 1. Deterministisch: gerechnet mit dem Wind-ERWARTUNGSWERT, danach gegen 40</span></span>
<span id="cb3-29"><a href="#cb3-29" aria-hidden="true" tabindex="-1"></a><span class="co"> Szenarien ausgewertet.</span></span>
<span id="cb3-30"><a href="#cb3-30" aria-hidden="true" tabindex="-1"></a><span class="co"> 2. Zweistufig: der Commitment-Plan sieht alle 40 Szenarien.</span></span>
<span id="cb3-31"><a href="#cb3-31" aria-hidden="true" tabindex="-1"></a><span class="co"> 3. Mit Versorgungssicherheit: die Nichtdeckung in den schlechtesten Faellen</span></span>
<span id="cb3-32"><a href="#cb3-32" aria-hidden="true" tabindex="-1"></a><span class="co"> wird begrenzt - und der Preis dafuer in Euro je vermiedener MWh</span></span>
<span id="cb3-33"><a href="#cb3-33" aria-hidden="true" tabindex="-1"></a><span class="co"> ausgewiesen.</span></span>
<span id="cb3-34"><a href="#cb3-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-35"><a href="#cb3-35" aria-hidden="true" tabindex="-1"></a><span class="co">Benoetigt: numpy, ortools</span></span>
<span id="cb3-36"><a href="#cb3-36" aria-hidden="true" tabindex="-1"></a><span class="co">&quot;&quot;&quot;</span></span>
<span id="cb3-37"><a href="#cb3-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-38"><a href="#cb3-38" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> __future__ <span class="im">import</span> annotations</span>
<span id="cb3-39"><a href="#cb3-39" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-40"><a href="#cb3-40" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> time</span>
<span id="cb3-41"><a href="#cb3-41" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-42"><a href="#cb3-42" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
<span id="cb3-43"><a href="#cb3-43" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> ortools.linear_solver <span class="im">import</span> pywraplp</span>
<span id="cb3-44"><a href="#cb3-44" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-45"><a href="#cb3-45" aria-hidden="true" tabindex="-1"></a><span class="co"># (Name, Mindestleistung, Nennleistung, Grenzkosten, Anfahrkosten, Mindestlaufzeit)</span></span>
<span id="cb3-46"><a href="#cb3-46" aria-hidden="true" tabindex="-1"></a>KRAFTWERKE <span class="op">=</span> [</span>
<span id="cb3-47"><a href="#cb3-47" aria-hidden="true" tabindex="-1"></a> (<span class="st">&quot;Kernblock&quot;</span>, <span class="dv">200</span>, <span class="dv">600</span>, <span class="dv">22</span>, <span class="dv">40_000</span>, <span class="dv">8</span>),</span>
<span id="cb3-48"><a href="#cb3-48" aria-hidden="true" tabindex="-1"></a> (<span class="st">&quot;Braunkohle&quot;</span>, <span class="dv">100</span>, <span class="dv">400</span>, <span class="dv">35</span>, <span class="dv">18_000</span>, <span class="dv">6</span>),</span>
<span id="cb3-49"><a href="#cb3-49" aria-hidden="true" tabindex="-1"></a> (<span class="st">&quot;Steinkohle&quot;</span>, <span class="dv">80</span>, <span class="dv">300</span>, <span class="dv">48</span>, <span class="dv">12_000</span>, <span class="dv">4</span>),</span>
<span id="cb3-50"><a href="#cb3-50" aria-hidden="true" tabindex="-1"></a> (<span class="st">&quot;Gas GuD&quot;</span>, <span class="dv">50</span>, <span class="dv">250</span>, <span class="dv">72</span>, <span class="dv">6_000</span>, <span class="dv">2</span>),</span>
<span id="cb3-51"><a href="#cb3-51" aria-hidden="true" tabindex="-1"></a> (<span class="st">&quot;Gasturbine&quot;</span>, <span class="dv">20</span>, <span class="dv">150</span>, <span class="dv">105</span>, <span class="dv">1_500</span>, <span class="dv">1</span>),</span>
<span id="cb3-52"><a href="#cb3-52" aria-hidden="true" tabindex="-1"></a>]</span>
<span id="cb3-53"><a href="#cb3-53" aria-hidden="true" tabindex="-1"></a>STUNDEN <span class="op">=</span> <span class="dv">24</span></span>
<span id="cb3-54"><a href="#cb3-54" aria-hidden="true" tabindex="-1"></a>SZENARIEN <span class="op">=</span> <span class="dv">40</span></span>
<span id="cb3-55"><a href="#cb3-55" aria-hidden="true" tabindex="-1"></a>FLAUTENANTEIL <span class="op">=</span> <span class="fl">0.15</span></span>
<span id="cb3-56"><a href="#cb3-56" aria-hidden="true" tabindex="-1"></a>ALPHA <span class="op">=</span> <span class="fl">0.90</span> <span class="co"># die schlechtesten 10 % der Szenarien</span></span>
<span id="cb3-57"><a href="#cb3-57" aria-hidden="true" tabindex="-1"></a>LASTABWURF <span class="op">=</span> <span class="fl">3_000.0</span> <span class="co"># EUR je nicht gedeckter MWh (&quot;value of lost load&quot;)</span></span>
<span id="cb3-58"><a href="#cb3-58" aria-hidden="true" tabindex="-1"></a>NIEDRIGER_ABWURFPREIS <span class="op">=</span> <span class="fl">300.0</span> <span class="co"># zum Vergleich: ein Marktpreisdeckel</span></span>
<span id="cb3-59"><a href="#cb3-59" aria-hidden="true" tabindex="-1"></a>SAAT <span class="op">=</span> <span class="dv">4</span></span>
<span id="cb3-60"><a href="#cb3-60" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-61"><a href="#cb3-61" aria-hidden="true" tabindex="-1"></a>_t <span class="op">=</span> np.arange(STUNDEN)</span>
<span id="cb3-62"><a href="#cb3-62" aria-hidden="true" tabindex="-1"></a>LAST <span class="op">=</span> <span class="dv">620</span> <span class="op">+</span> <span class="dv">260</span> <span class="op">*</span> np.sin((_t <span class="op">-</span> <span class="dv">7</span>) <span class="op">/</span> <span class="dv">24</span> <span class="op">*</span> <span class="dv">2</span> <span class="op">*</span> np.pi) <span class="op">+</span> <span class="dv">90</span> <span class="op">*</span> np.sin((_t <span class="op">-</span> <span class="dv">4</span>) <span class="op">/</span> <span class="dv">12</span> <span class="op">*</span> <span class="dv">2</span> <span class="op">*</span> np.pi)</span>
<span id="cb3-63"><a href="#cb3-63" aria-hidden="true" tabindex="-1"></a>WIND_ERWARTUNG <span class="op">=</span> np.maximum(<span class="fl">0.0</span>, <span class="dv">160</span> <span class="op">+</span> <span class="dv">130</span> <span class="op">*</span> np.sin((_t <span class="op">-</span> <span class="dv">14</span>) <span class="op">/</span> <span class="dv">24</span> <span class="op">*</span> <span class="dv">2</span> <span class="op">*</span> np.pi))</span>
<span id="cb3-64"><a href="#cb3-64" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-65"><a href="#cb3-65" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-66"><a href="#cb3-66" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> erzeuge_windszenarien(anzahl: <span class="bu">int</span> <span class="op">=</span> SZENARIEN, saat: <span class="bu">int</span> <span class="op">=</span> SAAT):</span>
<span id="cb3-67"><a href="#cb3-67" aria-hidden="true" tabindex="-1"></a> <span class="co">&quot;&quot;&quot;Windeinspeisung je Szenario und Stunde.</span></span>
<span id="cb3-68"><a href="#cb3-68" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-69"><a href="#cb3-69" aria-hidden="true" tabindex="-1"></a><span class="co"> Zwei Zutaten, die zusammen den Unterschied machen: eine breite</span></span>
<span id="cb3-70"><a href="#cb3-70" aria-hidden="true" tabindex="-1"></a><span class="co"> lognormale Streuung des Tagesniveaus - und in 15 % der Faelle eine</span></span>
<span id="cb3-71"><a href="#cb3-71" aria-hidden="true" tabindex="-1"></a><span class="co"> DUNKELFLAUTE, in der praktisch gar kein Wind weht. Solche seltenen,</span></span>
<span id="cb3-72"><a href="#cb3-72" aria-hidden="true" tabindex="-1"></a><span class="co"> extremen Faelle sind der Grund, warum der Erwartungswert als</span></span>
<span id="cb3-73"><a href="#cb3-73" aria-hidden="true" tabindex="-1"></a><span class="co"> Planungsgrundlage nicht genuegt.</span></span>
<span id="cb3-74"><a href="#cb3-74" aria-hidden="true" tabindex="-1"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb3-75"><a href="#cb3-75" aria-hidden="true" tabindex="-1"></a> rng <span class="op">=</span> np.random.default_rng(saat)</span>
<span id="cb3-76"><a href="#cb3-76" aria-hidden="true" tabindex="-1"></a> tagesniveau <span class="op">=</span> rng.lognormal(<span class="dv">0</span>, <span class="fl">0.40</span>, (anzahl, <span class="dv">1</span>))</span>
<span id="cb3-77"><a href="#cb3-77" aria-hidden="true" tabindex="-1"></a> wind <span class="op">=</span> np.clip(WIND_ERWARTUNG <span class="op">*</span> tagesniveau</span>
<span id="cb3-78"><a href="#cb3-78" aria-hidden="true" tabindex="-1"></a> <span class="op">+</span> rng.normal(<span class="dv">0</span>, <span class="dv">25</span>, (anzahl, STUNDEN)), <span class="dv">0</span>, <span class="dv">420</span>)</span>
<span id="cb3-79"><a href="#cb3-79" aria-hidden="true" tabindex="-1"></a> ist_flaute <span class="op">=</span> rng.random(anzahl) <span class="op">&lt;</span> FLAUTENANTEIL</span>
<span id="cb3-80"><a href="#cb3-80" aria-hidden="true" tabindex="-1"></a> wind[ist_flaute] <span class="op">*=</span> <span class="fl">0.05</span></span>
<span id="cb3-81"><a href="#cb3-81" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> wind, ist_flaute</span>
<span id="cb3-82"><a href="#cb3-82" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-83"><a href="#cb3-83" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-84"><a href="#cb3-84" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> plane(wind: np.ndarray, gewichte, cvar_grenze: <span class="bu">float</span> <span class="op">|</span> <span class="va">None</span> <span class="op">=</span> <span class="va">None</span>,</span>
<span id="cb3-85"><a href="#cb3-85" aria-hidden="true" tabindex="-1"></a> abwurfpreis: <span class="bu">float</span> <span class="op">=</span> <span class="va">None</span>, zeitlimit: <span class="bu">float</span> <span class="op">=</span> <span class="fl">300.0</span>):</span>
<span id="cb3-86"><a href="#cb3-86" aria-hidden="true" tabindex="-1"></a> <span class="co">&quot;&quot;&quot;Commitment (Stufe 1) und Fahrweise je Szenario (Stufe 2) in einem Modell.</span></span>
<span id="cb3-87"><a href="#cb3-87" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-88"><a href="#cb3-88" aria-hidden="true" tabindex="-1"></a><span class="co"> &#39;wind&#39; hat die Form (Szenarien, Stunden). Mit einer einzigen Zeile</span></span>
<span id="cb3-89"><a href="#cb3-89" aria-hidden="true" tabindex="-1"></a><span class="co"> Windprognose wird daraus die deterministische Planung.</span></span>
<span id="cb3-90"><a href="#cb3-90" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-91"><a href="#cb3-91" aria-hidden="true" tabindex="-1"></a><span class="co"> &#39;cvar_grenze&#39; begrenzt den CVaR der Nichtdeckung ueber die Szenarien -</span></span>
<span id="cb3-92"><a href="#cb3-92" aria-hidden="true" tabindex="-1"></a><span class="co"> dieselbe Rockafellar-Uryasev-Konstruktion wie im Kapitel CVaR, nur dass</span></span>
<span id="cb3-93"><a href="#cb3-93" aria-hidden="true" tabindex="-1"></a><span class="co"> hier keine Verluste in Euro, sondern Megawattstunden begrenzt werden.</span></span>
<span id="cb3-94"><a href="#cb3-94" aria-hidden="true" tabindex="-1"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb3-95"><a href="#cb3-95" aria-hidden="true" tabindex="-1"></a> abwurfpreis <span class="op">=</span> LASTABWURF <span class="cf">if</span> abwurfpreis <span class="kw">is</span> <span class="va">None</span> <span class="cf">else</span> abwurfpreis</span>
<span id="cb3-96"><a href="#cb3-96" aria-hidden="true" tabindex="-1"></a> anzahl_szenarien <span class="op">=</span> wind.shape[<span class="dv">0</span>]</span>
<span id="cb3-97"><a href="#cb3-97" aria-hidden="true" tabindex="-1"></a> anzahl_bloecke <span class="op">=</span> <span class="bu">len</span>(KRAFTWERKE)</span>
<span id="cb3-98"><a href="#cb3-98" aria-hidden="true" tabindex="-1"></a> solver <span class="op">=</span> pywraplp.Solver.CreateSolver(<span class="st">&quot;SCIP&quot;</span>)</span>
<span id="cb3-99"><a href="#cb3-99" aria-hidden="true" tabindex="-1"></a> solver.SetTimeLimit(<span class="bu">int</span>(zeitlimit <span class="op">*</span> <span class="dv">1000</span>))</span>
<span id="cb3-100"><a href="#cb3-100" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-101"><a href="#cb3-101" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- Stufe 1: binaer, szenariouebergreifend gleich --------------------</span></span>
<span id="cb3-102"><a href="#cb3-102" aria-hidden="true" tabindex="-1"></a> laeuft <span class="op">=</span> [[solver.BoolVar(<span class="ss">f&quot;laeuft_</span><span class="sc">{</span>k<span class="sc">}</span><span class="ss">_</span><span class="sc">{</span>t<span class="sc">}</span><span class="ss">&quot;</span>) <span class="cf">for</span> t <span class="kw">in</span> <span class="bu">range</span>(STUNDEN)]</span>
<span id="cb3-103"><a href="#cb3-103" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> k <span class="kw">in</span> <span class="bu">range</span>(anzahl_bloecke)]</span>
<span id="cb3-104"><a href="#cb3-104" aria-hidden="true" tabindex="-1"></a> faehrt_an <span class="op">=</span> [[solver.BoolVar(<span class="ss">f&quot;start_</span><span class="sc">{</span>k<span class="sc">}</span><span class="ss">_</span><span class="sc">{</span>t<span class="sc">}</span><span class="ss">&quot;</span>) <span class="cf">for</span> t <span class="kw">in</span> <span class="bu">range</span>(STUNDEN)]</span>
<span id="cb3-105"><a href="#cb3-105" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> k <span class="kw">in</span> <span class="bu">range</span>(anzahl_bloecke)]</span>
<span id="cb3-106"><a href="#cb3-106" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-107"><a href="#cb3-107" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- Stufe 2: kontinuierlich, je Szenario -----------------------------</span></span>
<span id="cb3-108"><a href="#cb3-108" aria-hidden="true" tabindex="-1"></a> leistung <span class="op">=</span> [[[solver.NumVar(<span class="dv">0</span>, KRAFTWERKE[k][<span class="dv">2</span>], <span class="ss">f&quot;p_</span><span class="sc">{</span>j<span class="sc">}</span><span class="ss">_</span><span class="sc">{</span>k<span class="sc">}</span><span class="ss">_</span><span class="sc">{</span>t<span class="sc">}</span><span class="ss">&quot;</span>)</span>
<span id="cb3-109"><a href="#cb3-109" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> t <span class="kw">in</span> <span class="bu">range</span>(STUNDEN)] <span class="cf">for</span> k <span class="kw">in</span> <span class="bu">range</span>(anzahl_bloecke)]</span>
<span id="cb3-110"><a href="#cb3-110" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> j <span class="kw">in</span> <span class="bu">range</span>(anzahl_szenarien)]</span>
<span id="cb3-111"><a href="#cb3-111" aria-hidden="true" tabindex="-1"></a> nichtdeckung <span class="op">=</span> [[solver.NumVar(<span class="dv">0</span>, solver.infinity(), <span class="ss">f&quot;y_</span><span class="sc">{</span>j<span class="sc">}</span><span class="ss">_</span><span class="sc">{</span>t<span class="sc">}</span><span class="ss">&quot;</span>)</span>
<span id="cb3-112"><a href="#cb3-112" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> t <span class="kw">in</span> <span class="bu">range</span>(STUNDEN)] <span class="cf">for</span> j <span class="kw">in</span> <span class="bu">range</span>(anzahl_szenarien)]</span>
<span id="cb3-113"><a href="#cb3-113" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-114"><a href="#cb3-114" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> k, (_, pmin, pmax, _, _, mindestlaufzeit) <span class="kw">in</span> <span class="bu">enumerate</span>(KRAFTWERKE):</span>
<span id="cb3-115"><a href="#cb3-115" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> t <span class="kw">in</span> <span class="bu">range</span>(STUNDEN):</span>
<span id="cb3-116"><a href="#cb3-116" aria-hidden="true" tabindex="-1"></a> <span class="co"># Anfahren erkennen: aus im Vortakt, an im aktuellen</span></span>
<span id="cb3-117"><a href="#cb3-117" aria-hidden="true" tabindex="-1"></a> vorher <span class="op">=</span> laeuft[k][t <span class="op">-</span> <span class="dv">1</span>] <span class="cf">if</span> t <span class="op">&gt;</span> <span class="dv">0</span> <span class="cf">else</span> <span class="dv">0</span></span>
<span id="cb3-118"><a href="#cb3-118" aria-hidden="true" tabindex="-1"></a> solver.Add(faehrt_an[k][t] <span class="op">&gt;=</span> laeuft[k][t] <span class="op">-</span> vorher)</span>
<span id="cb3-119"><a href="#cb3-119" aria-hidden="true" tabindex="-1"></a> <span class="co"># Mindestlaufzeit: wer anfaehrt, laeuft die naechsten Stunden weiter</span></span>
<span id="cb3-120"><a href="#cb3-120" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> spaeter <span class="kw">in</span> <span class="bu">range</span>(t, <span class="bu">min</span>(STUNDEN, t <span class="op">+</span> mindestlaufzeit)):</span>
<span id="cb3-121"><a href="#cb3-121" aria-hidden="true" tabindex="-1"></a> solver.Add(laeuft[k][spaeter] <span class="op">&gt;=</span> faehrt_an[k][t])</span>
<span id="cb3-122"><a href="#cb3-122" aria-hidden="true" tabindex="-1"></a> <span class="co"># Ein laufender Block liefert zwischen Mindest- und Nennleistung,</span></span>
<span id="cb3-123"><a href="#cb3-123" aria-hidden="true" tabindex="-1"></a> <span class="co"># ein stehender gar nichts. Das koppelt beide Stufen.</span></span>
<span id="cb3-124"><a href="#cb3-124" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> j <span class="kw">in</span> <span class="bu">range</span>(anzahl_szenarien):</span>
<span id="cb3-125"><a href="#cb3-125" aria-hidden="true" tabindex="-1"></a> solver.Add(leistung[j][k][t] <span class="op">&gt;=</span> pmin <span class="op">*</span> laeuft[k][t])</span>
<span id="cb3-126"><a href="#cb3-126" aria-hidden="true" tabindex="-1"></a> solver.Add(leistung[j][k][t] <span class="op">&lt;=</span> pmax <span class="op">*</span> laeuft[k][t])</span>
<span id="cb3-127"><a href="#cb3-127" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-128"><a href="#cb3-128" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> j <span class="kw">in</span> <span class="bu">range</span>(anzahl_szenarien):</span>
<span id="cb3-129"><a href="#cb3-129" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> t <span class="kw">in</span> <span class="bu">range</span>(STUNDEN):</span>
<span id="cb3-130"><a href="#cb3-130" aria-hidden="true" tabindex="-1"></a> solver.Add(<span class="bu">sum</span>(leistung[j][k][t] <span class="cf">for</span> k <span class="kw">in</span> <span class="bu">range</span>(anzahl_bloecke))</span>
<span id="cb3-131"><a href="#cb3-131" aria-hidden="true" tabindex="-1"></a> <span class="op">+</span> <span class="bu">float</span>(wind[j, t]) <span class="op">+</span> nichtdeckung[j][t] <span class="op">&gt;=</span> LAST[t])</span>
<span id="cb3-132"><a href="#cb3-132" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-133"><a href="#cb3-133" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- Versorgungssicherheit als CVaR-Schranke --------------------------</span></span>
<span id="cb3-134"><a href="#cb3-134" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> cvar_grenze <span class="kw">is</span> <span class="kw">not</span> <span class="va">None</span>:</span>
<span id="cb3-135"><a href="#cb3-135" aria-hidden="true" tabindex="-1"></a> schwelle <span class="op">=</span> solver.NumVar(<span class="op">-</span>solver.infinity(), solver.infinity(), <span class="st">&quot;schwelle&quot;</span>)</span>
<span id="cb3-136"><a href="#cb3-136" aria-hidden="true" tabindex="-1"></a> ueberschuss <span class="op">=</span> [solver.NumVar(<span class="dv">0</span>, solver.infinity(), <span class="ss">f&quot;u_</span><span class="sc">{</span>j<span class="sc">}</span><span class="ss">&quot;</span>)</span>
<span id="cb3-137"><a href="#cb3-137" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> j <span class="kw">in</span> <span class="bu">range</span>(anzahl_szenarien)]</span>
<span id="cb3-138"><a href="#cb3-138" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> j <span class="kw">in</span> <span class="bu">range</span>(anzahl_szenarien):</span>
<span id="cb3-139"><a href="#cb3-139" aria-hidden="true" tabindex="-1"></a> solver.Add(ueberschuss[j] <span class="op">&gt;=</span> <span class="bu">sum</span>(nichtdeckung[j][t]</span>
<span id="cb3-140"><a href="#cb3-140" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> t <span class="kw">in</span> <span class="bu">range</span>(STUNDEN)) <span class="op">-</span> schwelle)</span>
<span id="cb3-141"><a href="#cb3-141" aria-hidden="true" tabindex="-1"></a> solver.Add(schwelle <span class="op">+</span> (<span class="fl">1.0</span> <span class="op">/</span> (anzahl_szenarien <span class="op">*</span> (<span class="dv">1</span> <span class="op">-</span> ALPHA)))</span>
<span id="cb3-142"><a href="#cb3-142" aria-hidden="true" tabindex="-1"></a> <span class="op">*</span> <span class="bu">sum</span>(ueberschuss) <span class="op">&lt;=</span> cvar_grenze)</span>
<span id="cb3-143"><a href="#cb3-143" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-144"><a href="#cb3-144" aria-hidden="true" tabindex="-1"></a> anfahrkosten <span class="op">=</span> <span class="bu">sum</span>(KRAFTWERKE[k][<span class="dv">4</span>] <span class="op">*</span> faehrt_an[k][t]</span>
<span id="cb3-145"><a href="#cb3-145" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> k <span class="kw">in</span> <span class="bu">range</span>(anzahl_bloecke) <span class="cf">for</span> t <span class="kw">in</span> <span class="bu">range</span>(STUNDEN))</span>
<span id="cb3-146"><a href="#cb3-146" aria-hidden="true" tabindex="-1"></a> betriebskosten <span class="op">=</span> <span class="bu">sum</span>(</span>
<span id="cb3-147"><a href="#cb3-147" aria-hidden="true" tabindex="-1"></a> gewichte[j] <span class="op">*</span> <span class="bu">sum</span>(KRAFTWERKE[k][<span class="dv">3</span>] <span class="op">*</span> leistung[j][k][t]</span>
<span id="cb3-148"><a href="#cb3-148" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> k <span class="kw">in</span> <span class="bu">range</span>(anzahl_bloecke) <span class="cf">for</span> t <span class="kw">in</span> <span class="bu">range</span>(STUNDEN))</span>
<span id="cb3-149"><a href="#cb3-149" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> j <span class="kw">in</span> <span class="bu">range</span>(anzahl_szenarien))</span>
<span id="cb3-150"><a href="#cb3-150" aria-hidden="true" tabindex="-1"></a> abwurfkosten <span class="op">=</span> <span class="bu">sum</span>(gewichte[j] <span class="op">*</span> abwurfpreis</span>
<span id="cb3-151"><a href="#cb3-151" aria-hidden="true" tabindex="-1"></a> <span class="op">*</span> <span class="bu">sum</span>(nichtdeckung[j][t] <span class="cf">for</span> t <span class="kw">in</span> <span class="bu">range</span>(STUNDEN))</span>
<span id="cb3-152"><a href="#cb3-152" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> j <span class="kw">in</span> <span class="bu">range</span>(anzahl_szenarien))</span>
<span id="cb3-153"><a href="#cb3-153" aria-hidden="true" tabindex="-1"></a> solver.Minimize(anfahrkosten <span class="op">+</span> betriebskosten <span class="op">+</span> abwurfkosten)</span>
<span id="cb3-154"><a href="#cb3-154" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-155"><a href="#cb3-155" aria-hidden="true" tabindex="-1"></a> beginn <span class="op">=</span> time.perf_counter()</span>
<span id="cb3-156"><a href="#cb3-156" aria-hidden="true" tabindex="-1"></a> status <span class="op">=</span> solver.Solve()</span>
<span id="cb3-157"><a href="#cb3-157" aria-hidden="true" tabindex="-1"></a> dauer <span class="op">=</span> time.perf_counter() <span class="op">-</span> beginn</span>
<span id="cb3-158"><a href="#cb3-158" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> status <span class="kw">not</span> <span class="kw">in</span> (pywraplp.Solver.OPTIMAL, pywraplp.Solver.FEASIBLE):</span>
<span id="cb3-159"><a href="#cb3-159" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="va">None</span>, dauer, <span class="va">False</span></span>
<span id="cb3-160"><a href="#cb3-160" aria-hidden="true" tabindex="-1"></a> plan <span class="op">=</span> np.array([[laeuft[k][t].solution_value() <span class="cf">for</span> t <span class="kw">in</span> <span class="bu">range</span>(STUNDEN)]</span>
<span id="cb3-161"><a href="#cb3-161" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> k <span class="kw">in</span> <span class="bu">range</span>(anzahl_bloecke)]).<span class="bu">round</span>()</span>
<span id="cb3-162"><a href="#cb3-162" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> plan, dauer, status <span class="op">==</span> pywraplp.Solver.OPTIMAL</span>
<span id="cb3-163"><a href="#cb3-163" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-164"><a href="#cb3-164" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-165"><a href="#cb3-165" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> bewerte(plan: np.ndarray, wind: np.ndarray, abwurfpreis: <span class="bu">float</span> <span class="op">=</span> <span class="va">None</span>):</span>
<span id="cb3-166"><a href="#cb3-166" aria-hidden="true" tabindex="-1"></a> <span class="co">&quot;&quot;&quot;Commitment steht fest - nur noch die Fahrweise je Szenario optimieren.</span></span>
<span id="cb3-167"><a href="#cb3-167" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-168"><a href="#cb3-168" aria-hidden="true" tabindex="-1"></a><span class="co"> Das ist die ehrliche Bewertung eines Plans: Er wird der Wirklichkeit</span></span>
<span id="cb3-169"><a href="#cb3-169" aria-hidden="true" tabindex="-1"></a><span class="co"> ausgesetzt und darf nur noch das anpassen, was sich am Tag selbst</span></span>
<span id="cb3-170"><a href="#cb3-170" aria-hidden="true" tabindex="-1"></a><span class="co"> anpassen laesst.</span></span>
<span id="cb3-171"><a href="#cb3-171" aria-hidden="true" tabindex="-1"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb3-172"><a href="#cb3-172" aria-hidden="true" tabindex="-1"></a> abwurfpreis <span class="op">=</span> LASTABWURF <span class="cf">if</span> abwurfpreis <span class="kw">is</span> <span class="va">None</span> <span class="cf">else</span> abwurfpreis</span>
<span id="cb3-173"><a href="#cb3-173" aria-hidden="true" tabindex="-1"></a> anzahl_bloecke <span class="op">=</span> <span class="bu">len</span>(KRAFTWERKE)</span>
<span id="cb3-174"><a href="#cb3-174" aria-hidden="true" tabindex="-1"></a> kosten, fehlmengen <span class="op">=</span> [], []</span>
<span id="cb3-175"><a href="#cb3-175" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> j <span class="kw">in</span> <span class="bu">range</span>(wind.shape[<span class="dv">0</span>]):</span>
<span id="cb3-176"><a href="#cb3-176" aria-hidden="true" tabindex="-1"></a> solver <span class="op">=</span> pywraplp.Solver.CreateSolver(<span class="st">&quot;GLOP&quot;</span>)</span>
<span id="cb3-177"><a href="#cb3-177" aria-hidden="true" tabindex="-1"></a> leistung <span class="op">=</span> [[solver.NumVar(<span class="dv">0</span>, KRAFTWERKE[k][<span class="dv">2</span>], <span class="ss">f&quot;p_</span><span class="sc">{</span>k<span class="sc">}</span><span class="ss">_</span><span class="sc">{</span>t<span class="sc">}</span><span class="ss">&quot;</span>)</span>
<span id="cb3-178"><a href="#cb3-178" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> t <span class="kw">in</span> <span class="bu">range</span>(STUNDEN)] <span class="cf">for</span> k <span class="kw">in</span> <span class="bu">range</span>(anzahl_bloecke)]</span>
<span id="cb3-179"><a href="#cb3-179" aria-hidden="true" tabindex="-1"></a> fehlt <span class="op">=</span> [solver.NumVar(<span class="dv">0</span>, solver.infinity(), <span class="ss">f&quot;y_</span><span class="sc">{</span>t<span class="sc">}</span><span class="ss">&quot;</span>)</span>
<span id="cb3-180"><a href="#cb3-180" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> t <span class="kw">in</span> <span class="bu">range</span>(STUNDEN)]</span>
<span id="cb3-181"><a href="#cb3-181" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> k, (_, pmin, pmax, _, _, _) <span class="kw">in</span> <span class="bu">enumerate</span>(KRAFTWERKE):</span>
<span id="cb3-182"><a href="#cb3-182" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> t <span class="kw">in</span> <span class="bu">range</span>(STUNDEN):</span>
<span id="cb3-183"><a href="#cb3-183" aria-hidden="true" tabindex="-1"></a> solver.Add(leistung[k][t] <span class="op">&gt;=</span> pmin <span class="op">*</span> plan[k, t])</span>
<span id="cb3-184"><a href="#cb3-184" aria-hidden="true" tabindex="-1"></a> solver.Add(leistung[k][t] <span class="op">&lt;=</span> pmax <span class="op">*</span> plan[k, t])</span>
<span id="cb3-185"><a href="#cb3-185" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> t <span class="kw">in</span> <span class="bu">range</span>(STUNDEN):</span>
<span id="cb3-186"><a href="#cb3-186" aria-hidden="true" tabindex="-1"></a> solver.Add(<span class="bu">sum</span>(leistung[k][t] <span class="cf">for</span> k <span class="kw">in</span> <span class="bu">range</span>(anzahl_bloecke))</span>
<span id="cb3-187"><a href="#cb3-187" aria-hidden="true" tabindex="-1"></a> <span class="op">+</span> <span class="bu">float</span>(wind[j, t]) <span class="op">+</span> fehlt[t] <span class="op">&gt;=</span> LAST[t])</span>
<span id="cb3-188"><a href="#cb3-188" aria-hidden="true" tabindex="-1"></a> solver.Minimize(</span>
<span id="cb3-189"><a href="#cb3-189" aria-hidden="true" tabindex="-1"></a> <span class="bu">sum</span>(KRAFTWERKE[k][<span class="dv">3</span>] <span class="op">*</span> leistung[k][t]</span>
<span id="cb3-190"><a href="#cb3-190" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> k <span class="kw">in</span> <span class="bu">range</span>(anzahl_bloecke) <span class="cf">for</span> t <span class="kw">in</span> <span class="bu">range</span>(STUNDEN))</span>
<span id="cb3-191"><a href="#cb3-191" aria-hidden="true" tabindex="-1"></a> <span class="op">+</span> <span class="bu">sum</span>(abwurfpreis <span class="op">*</span> fehlt[t] <span class="cf">for</span> t <span class="kw">in</span> <span class="bu">range</span>(STUNDEN)))</span>
<span id="cb3-192"><a href="#cb3-192" aria-hidden="true" tabindex="-1"></a> solver.Solve()</span>
<span id="cb3-193"><a href="#cb3-193" aria-hidden="true" tabindex="-1"></a> kosten.append(solver.Objective().Value())</span>
<span id="cb3-194"><a href="#cb3-194" aria-hidden="true" tabindex="-1"></a> fehlmengen.append(<span class="bu">sum</span>(f.solution_value() <span class="cf">for</span> f <span class="kw">in</span> fehlt))</span>
<span id="cb3-195"><a href="#cb3-195" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-196"><a href="#cb3-196" aria-hidden="true" tabindex="-1"></a> anfahrten <span class="op">=</span> <span class="bu">sum</span>(KRAFTWERKE[k][<span class="dv">4</span>]</span>
<span id="cb3-197"><a href="#cb3-197" aria-hidden="true" tabindex="-1"></a> <span class="op">*</span> <span class="bu">max</span>(<span class="fl">0.0</span>, plan[k, t] <span class="op">-</span> (plan[k, t <span class="op">-</span> <span class="dv">1</span>] <span class="cf">if</span> t <span class="op">&gt;</span> <span class="dv">0</span> <span class="cf">else</span> <span class="fl">0.0</span>))</span>
<span id="cb3-198"><a href="#cb3-198" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> k <span class="kw">in</span> <span class="bu">range</span>(anzahl_bloecke) <span class="cf">for</span> t <span class="kw">in</span> <span class="bu">range</span>(STUNDEN))</span>
<span id="cb3-199"><a href="#cb3-199" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> np.array(kosten) <span class="op">+</span> anfahrten, np.array(fehlmengen)</span>
<span id="cb3-200"><a href="#cb3-200" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-201"><a href="#cb3-201" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-202"><a href="#cb3-202" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> cvar(werte: np.ndarray, alpha: <span class="bu">float</span> <span class="op">=</span> ALPHA) <span class="op">-&gt;</span> <span class="bu">float</span>:</span>
<span id="cb3-203"><a href="#cb3-203" aria-hidden="true" tabindex="-1"></a> <span class="co">&quot;&quot;&quot;Mittelwert der schlechtesten (1-alpha) Faelle.&quot;&quot;&quot;</span></span>
<span id="cb3-204"><a href="#cb3-204" aria-hidden="true" tabindex="-1"></a> schwelle <span class="op">=</span> np.quantile(werte, alpha)</span>
<span id="cb3-205"><a href="#cb3-205" aria-hidden="true" tabindex="-1"></a> schlechteste <span class="op">=</span> werte[werte <span class="op">&gt;=</span> schwelle]</span>
<span id="cb3-206"><a href="#cb3-206" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="bu">float</span>(schlechteste.mean()) <span class="cf">if</span> <span class="bu">len</span>(schlechteste) <span class="cf">else</span> <span class="fl">0.0</span></span>
<span id="cb3-207"><a href="#cb3-207" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-208"><a href="#cb3-208" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-209"><a href="#cb3-209" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> zeige(name: <span class="bu">str</span>, plan, wind, abwurfpreis: <span class="bu">float</span> <span class="op">=</span> <span class="va">None</span>) <span class="op">-&gt;</span> <span class="bu">dict</span>:</span>
<span id="cb3-210"><a href="#cb3-210" aria-hidden="true" tabindex="-1"></a> kosten, fehl <span class="op">=</span> bewerte(plan, wind, abwurfpreis)</span>
<span id="cb3-211"><a href="#cb3-211" aria-hidden="true" tabindex="-1"></a> kennzahlen <span class="op">=</span> {<span class="st">&quot;mittel&quot;</span>: kosten.mean(), <span class="st">&quot;max&quot;</span>: kosten.<span class="bu">max</span>(),</span>
<span id="cb3-212"><a href="#cb3-212" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;fehl_mittel&quot;</span>: fehl.mean(), <span class="st">&quot;fehl_cvar&quot;</span>: cvar(fehl),</span>
<span id="cb3-213"><a href="#cb3-213" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;betroffen&quot;</span>: <span class="bu">int</span>((fehl <span class="op">&gt;</span> <span class="fl">0.01</span>).<span class="bu">sum</span>()),</span>
<span id="cb3-214"><a href="#cb3-214" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;blockstunden&quot;</span>: <span class="bu">int</span>(plan.<span class="bu">sum</span>())}</span>
<span id="cb3-215"><a href="#cb3-215" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; </span><span class="sc">{</span>name<span class="sc">:&lt;32}</span><span class="ss"> </span><span class="sc">{</span>kennzahlen[<span class="st">&#39;mittel&#39;</span>]<span class="sc">:&gt;10,.0f}</span><span class="ss"> </span><span class="sc">{</span>kennzahlen[<span class="st">&#39;max&#39;</span>]<span class="sc">:&gt;11,.0f}</span><span class="ss"> &quot;</span></span>
<span id="cb3-216"><a href="#cb3-216" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;</span><span class="sc">{</span>kennzahlen[<span class="st">&#39;fehl_mittel&#39;</span>]<span class="sc">:&gt;9.1f}</span><span class="ss"> </span><span class="sc">{</span>kennzahlen[<span class="st">&#39;fehl_cvar&#39;</span>]<span class="sc">:&gt;10.1f}</span><span class="ss"> &quot;</span></span>
<span id="cb3-217"><a href="#cb3-217" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;</span><span class="sc">{</span>kennzahlen[<span class="st">&#39;betroffen&#39;</span>]<span class="sc">:&gt;6}</span><span class="ss">/</span><span class="sc">{</span><span class="bu">len</span>(fehl)<span class="sc">}</span><span class="ss">&quot;</span>)</span>
<span id="cb3-218"><a href="#cb3-218" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> kennzahlen</span>
<span id="cb3-219"><a href="#cb3-219" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-220"><a href="#cb3-220" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-221"><a href="#cb3-221" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="va">__name__</span> <span class="op">==</span> <span class="st">&quot;__main__&quot;</span>:</span>
<span id="cb3-222"><a href="#cb3-222" aria-hidden="true" tabindex="-1"></a> wind, ist_flaute <span class="op">=</span> erzeuge_windszenarien()</span>
<span id="cb3-223"><a href="#cb3-223" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-224"><a href="#cb3-224" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;=&quot;</span> <span class="op">*</span> <span class="dv">88</span>)</span>
<span id="cb3-225"><a href="#cb3-225" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; KRAFTWERKSEINSATZ: DER PLAN STEHT, BEVOR DER WIND WEHT&quot;</span>)</span>
<span id="cb3-226"><a href="#cb3-226" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;=&quot;</span> <span class="op">*</span> <span class="dv">88</span>)</span>
<span id="cb3-227"><a href="#cb3-227" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;</span><span class="sc">{</span><span class="bu">len</span>(KRAFTWERKE)<span class="sc">}</span><span class="ss"> Bloecke, </span><span class="sc">{</span>STUNDEN<span class="sc">}</span><span class="ss"> Stunden, </span><span class="sc">{</span>SZENARIEN<span class="sc">}</span><span class="ss"> Windszenarien &quot;</span></span>
<span id="cb3-228"><a href="#cb3-228" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;(davon </span><span class="sc">{</span><span class="bu">int</span>(ist_flaute.<span class="bu">sum</span>())<span class="sc">}</span><span class="ss"> Dunkelflauten).&quot;</span>)</span>
<span id="cb3-229"><a href="#cb3-229" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;Last </span><span class="sc">{</span>LAST<span class="sc">.</span><span class="bu">min</span>()<span class="sc">:.0f}</span><span class="ss"> bis </span><span class="sc">{</span>LAST<span class="sc">.</span><span class="bu">max</span>()<span class="sc">:.0f}</span><span class="ss"> MW, &quot;</span></span>
<span id="cb3-230"><a href="#cb3-230" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;Wind im Erwartungswert </span><span class="sc">{</span>WIND_ERWARTUNG<span class="sc">.</span><span class="bu">min</span>()<span class="sc">:.0f}</span><span class="ss"> bis &quot;</span></span>
<span id="cb3-231"><a href="#cb3-231" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;</span><span class="sc">{</span>WIND_ERWARTUNG<span class="sc">.</span><span class="bu">max</span>()<span class="sc">:.0f}</span><span class="ss"> MW.&quot;</span>)</span>
<span id="cb3-232"><a href="#cb3-232" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;Nicht gedeckte Last kostet </span><span class="sc">{</span>LASTABWURF<span class="sc">:,.0f}</span><span class="ss"> EUR je MWh.</span><span class="ch">\n</span><span class="ss">&quot;</span>)</span>
<span id="cb3-233"><a href="#cb3-233" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-234"><a href="#cb3-234" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; </span><span class="sc">{</span><span class="st">&#39;Planungsgrundlage&#39;</span><span class="sc">:&lt;32}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;Kosten&#39;</span><span class="sc">:&gt;10}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;Kosten&#39;</span><span class="sc">:&gt;11}</span><span class="ss"> &quot;</span></span>
<span id="cb3-235"><a href="#cb3-235" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;</span><span class="sc">{</span><span class="st">&#39;Fehlmenge&#39;</span><span class="sc">:&gt;9}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;Fehlmenge&#39;</span><span class="sc">:&gt;10}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;Szen. mit&#39;</span><span class="sc">:&gt;12}</span><span class="ss">&quot;</span>)</span>
<span id="cb3-236"><a href="#cb3-236" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; </span><span class="sc">{</span><span class="st">&#39;&#39;</span><span class="sc">:&lt;32}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;im Mittel&#39;</span><span class="sc">:&gt;10}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;schlimmst.&#39;</span><span class="sc">:&gt;11}</span><span class="ss"> &quot;</span></span>
<span id="cb3-237"><a href="#cb3-237" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;</span><span class="sc">{</span><span class="st">&#39;Mittel&#39;</span><span class="sc">:&gt;9}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;CVaR 90%&#39;</span><span class="sc">:&gt;10}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;Abwurf&#39;</span><span class="sc">:&gt;12}</span><span class="ss">&quot;</span>)</span>
<span id="cb3-238"><a href="#cb3-238" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; &quot;</span> <span class="op">+</span> <span class="st">&quot;-&quot;</span> <span class="op">*</span> <span class="dv">86</span>)</span>
<span id="cb3-239"><a href="#cb3-239" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-240"><a href="#cb3-240" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- 1. Deterministisch ----------------------------------------------</span></span>
<span id="cb3-241"><a href="#cb3-241" aria-hidden="true" tabindex="-1"></a> plan_det, dauer_det, _ <span class="op">=</span> plane(WIND_ERWARTUNG.reshape(<span class="dv">1</span>, <span class="op">-</span><span class="dv">1</span>), [<span class="fl">1.0</span>])</span>
<span id="cb3-242"><a href="#cb3-242" aria-hidden="true" tabindex="-1"></a> det <span class="op">=</span> zeige(<span class="st">&quot;nur Wind-Erwartungswert&quot;</span>, plan_det, wind)</span>
<span id="cb3-243"><a href="#cb3-243" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-244"><a href="#cb3-244" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- 2. Zweistufig, risikoneutral ------------------------------------</span></span>
<span id="cb3-245"><a href="#cb3-245" aria-hidden="true" tabindex="-1"></a> gleich <span class="op">=</span> [<span class="fl">1.0</span> <span class="op">/</span> SZENARIEN] <span class="op">*</span> SZENARIEN</span>
<span id="cb3-246"><a href="#cb3-246" aria-hidden="true" tabindex="-1"></a> plan_sto, dauer_sto, optimal_sto <span class="op">=</span> plane(wind, gleich)</span>
<span id="cb3-247"><a href="#cb3-247" aria-hidden="true" tabindex="-1"></a> sto <span class="op">=</span> zeige(<span class="st">&quot;alle 40 Szenarien&quot;</span>, plan_sto, wind)</span>
<span id="cb3-248"><a href="#cb3-248" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-249"><a href="#cb3-249" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- 3. Mit Versorgungssicherheit ------------------------------------</span></span>
<span id="cb3-250"><a href="#cb3-250" aria-hidden="true" tabindex="-1"></a> plan_sicher, dauer_sicher, optimal_sicher <span class="op">=</span> plane(wind, gleich, cvar_grenze<span class="op">=</span><span class="fl">0.0</span>)</span>
<span id="cb3-251"><a href="#cb3-251" aria-hidden="true" tabindex="-1"></a> sicher <span class="op">=</span> zeige(<span class="st">&quot;+ Nichtdeckung CVaR 90 % = 0&quot;</span>, plan_sicher, wind)</span>
<span id="cb3-252"><a href="#cb3-252" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-253"><a href="#cb3-253" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;</span><span class="ch">\n</span><span class="ss"> Rechenzeiten: </span><span class="sc">{</span>dauer_det<span class="sc">:.1f}</span><span class="ss">s / </span><span class="sc">{</span>dauer_sto<span class="sc">:.1f}</span><span class="ss">s / </span><span class="sc">{</span>dauer_sicher<span class="sc">:.1f}</span><span class="ss">s &quot;</span></span>
<span id="cb3-254"><a href="#cb3-254" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;(alle beweisbar optimal: </span><span class="sc">{</span>optimal_sto <span class="kw">and</span> optimal_sicher<span class="sc">}</span><span class="ss">)&quot;</span>)</span>
<span id="cb3-255"><a href="#cb3-255" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-256"><a href="#cb3-256" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- Was die Zeilen bedeuten -----------------------------------------</span></span>
<span id="cb3-257"><a href="#cb3-257" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;</span><span class="ch">\n</span><span class="st">&quot;</span> <span class="op">+</span> <span class="st">&quot;-&quot;</span> <span class="op">*</span> <span class="dv">88</span>)</span>
<span id="cb3-258"><a href="#cb3-258" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;Was der Erwartungswert-Plan anrichtet</span><span class="ch">\n</span><span class="st">&quot;</span>)</span>
<span id="cb3-259"><a href="#cb3-259" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; Er ist auf dem Papier der billigste - gerechnet auf den mittleren&quot;</span>)</span>
<span id="cb3-260"><a href="#cb3-260" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; Wind kostet er weniger als jeder andere. In der Wirklichkeit liegt&quot;</span>)</span>
<span id="cb3-261"><a href="#cb3-261" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; er </span><span class="sc">{</span>det[<span class="st">&#39;mittel&#39;</span>] <span class="op">/</span> sto[<span class="st">&#39;mittel&#39;</span>] <span class="op">-</span> <span class="dv">1</span><span class="sc">:+.0%}</span><span class="ss"> ueber dem zweistufigen Plan, und sein &quot;</span></span>
<span id="cb3-262"><a href="#cb3-262" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;schlimmster Tag&quot;</span>)</span>
<span id="cb3-263"><a href="#cb3-263" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; kostet </span><span class="sc">{</span>det[<span class="st">&#39;max&#39;</span>] <span class="op">/</span> sto[<span class="st">&#39;max&#39;</span>]<span class="sc">:.1f}</span><span class="ss">-mal so viel.&quot;</span>)</span>
<span id="cb3-264"><a href="#cb3-264" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;</span><span class="ch">\n</span><span class="ss"> Der Grund steht in der letzten Spalte: In </span><span class="sc">{</span>det[<span class="st">&#39;betroffen&#39;</span>]<span class="sc">}</span><span class="ss"> von </span><span class="sc">{</span>SZENARIEN<span class="sc">}</span><span class="ss"> &quot;</span></span>
<span id="cb3-265"><a href="#cb3-265" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;Szenarien muss&quot;</span>)</span>
<span id="cb3-266"><a href="#cb3-266" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; Last abgeworfen werden. Was fehlt, sind nicht Kraftwerke, sondern&quot;</span>)</span>
<span id="cb3-267"><a href="#cb3-267" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; ANGEFAHRENE Kraftwerke - und ein Block mit acht Stunden&quot;</span>)</span>
<span id="cb3-268"><a href="#cb3-268" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; Mindestlaufzeit laesst sich um 18 Uhr nicht mehr herbeirufen.&quot;</span>)</span>
<span id="cb3-269"><a href="#cb3-269" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-270"><a href="#cb3-270" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;</span><span class="ch">\n</span><span class="ss"> Der Unterschied im Plan ist klein:&quot;</span>)</span>
<span id="cb3-271"><a href="#cb3-271" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> name, plan <span class="kw">in</span> [(<span class="st">&quot;Erwartungswert&quot;</span>, plan_det), (<span class="st">&quot;zweistufig&quot;</span>, plan_sto),</span>
<span id="cb3-272"><a href="#cb3-272" aria-hidden="true" tabindex="-1"></a> (<span class="st">&quot;mit Sicherheit&quot;</span>, plan_sicher)]:</span>
<span id="cb3-273"><a href="#cb3-273" aria-hidden="true" tabindex="-1"></a> laufend <span class="op">=</span> plan.<span class="bu">sum</span>(axis<span class="op">=</span><span class="dv">0</span>).astype(<span class="bu">int</span>)</span>
<span id="cb3-274"><a href="#cb3-274" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; </span><span class="sc">{</span>name<span class="sc">:&lt;16}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;&#39;</span><span class="sc">.</span>join(<span class="bu">str</span>(x) <span class="cf">for</span> x <span class="kw">in</span> laufend)<span class="sc">}</span><span class="ss"> &quot;</span></span>
<span id="cb3-275"><a href="#cb3-275" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;(</span><span class="sc">{</span><span class="bu">int</span>(plan.<span class="bu">sum</span>())<span class="sc">}</span><span class="ss"> Blockstunden)&quot;</span>)</span>
<span id="cb3-276"><a href="#cb3-276" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;</span><span class="ch">\n</span><span class="ss"> Der zweistufige Plan haelt </span><span class="sc">{</span>sto[<span class="st">&#39;blockstunden&#39;</span>] <span class="op">-</span> det[<span class="st">&#39;blockstunden&#39;</span>]<span class="sc">}</span><span class="ss"> &quot;</span></span>
<span id="cb3-277"><a href="#cb3-277" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;Blockstunden mehr vor - das genuegt,&quot;</span>)</span>
<span id="cb3-278"><a href="#cb3-278" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; um alle </span><span class="sc">{</span>det[<span class="st">&#39;betroffen&#39;</span>]<span class="sc">}</span><span class="ss"> Lastabwuerfe zu vermeiden.&quot;</span>)</span>
<span id="cb3-279"><a href="#cb3-279" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-280"><a href="#cb3-280" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- Der Preis der Sicherheit ----------------------------------------</span></span>
<span id="cb3-281"><a href="#cb3-281" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;</span><span class="ch">\n</span><span class="st">&quot;</span> <span class="op">+</span> <span class="st">&quot;-&quot;</span> <span class="op">*</span> <span class="dv">88</span>)</span>
<span id="cb3-282"><a href="#cb3-282" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;Was Versorgungssicherheit kostet</span><span class="ch">\n</span><span class="st">&quot;</span>)</span>
<span id="cb3-283"><a href="#cb3-283" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; Bei </span><span class="sc">{</span>LASTABWURF<span class="sc">:,.0f}</span><span class="ss"> EUR/MWh kostet die CVaR-Schranke NICHTS: Der&quot;</span>)</span>
<span id="cb3-284"><a href="#cb3-284" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; risikoneutrale Plan haelt sie schon ein. Das ist kein Zufall - bei&quot;</span>)</span>
<span id="cb3-285"><a href="#cb3-285" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; diesem Preis lohnt sich Vorhaltung bereits im Erwartungswert.&quot;</span>)</span>
<span id="cb3-286"><a href="#cb3-286" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;</span><span class="ch">\n</span><span class="st"> Interessant wird die Schranke dort, wo der Schaden ZU NIEDRIG&quot;</span>)</span>
<span id="cb3-287"><a href="#cb3-287" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; bepreist ist. Dieselbe Rechnung mit einem Marktpreisdeckel von&quot;</span>)</span>
<span id="cb3-288"><a href="#cb3-288" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; </span><span class="sc">{</span>NIEDRIGER_ABWURFPREIS<span class="sc">:,.0f}</span><span class="ss"> EUR/MWh statt </span><span class="sc">{</span>LASTABWURF<span class="sc">:,.0f}</span><span class="ss">:</span><span class="ch">\n</span><span class="ss">&quot;</span>)</span>
<span id="cb3-289"><a href="#cb3-289" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-290"><a href="#cb3-290" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; </span><span class="sc">{</span><span class="st">&#39;Planungsgrundlage&#39;</span><span class="sc">:&lt;32}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;Kosten&#39;</span><span class="sc">:&gt;10}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;Kosten&#39;</span><span class="sc">:&gt;11}</span><span class="ss"> &quot;</span></span>
<span id="cb3-291"><a href="#cb3-291" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;</span><span class="sc">{</span><span class="st">&#39;Fehlmenge&#39;</span><span class="sc">:&gt;9}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;Fehlmenge&#39;</span><span class="sc">:&gt;10}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;Szen. mit&#39;</span><span class="sc">:&gt;12}</span><span class="ss">&quot;</span>)</span>
<span id="cb3-292"><a href="#cb3-292" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; </span><span class="sc">{</span><span class="st">&#39;&#39;</span><span class="sc">:&lt;32}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;im Mittel&#39;</span><span class="sc">:&gt;10}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;schlimmst.&#39;</span><span class="sc">:&gt;11}</span><span class="ss"> &quot;</span></span>
<span id="cb3-293"><a href="#cb3-293" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;</span><span class="sc">{</span><span class="st">&#39;Mittel&#39;</span><span class="sc">:&gt;9}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;CVaR 90%&#39;</span><span class="sc">:&gt;10}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;Abwurf&#39;</span><span class="sc">:&gt;12}</span><span class="ss">&quot;</span>)</span>
<span id="cb3-294"><a href="#cb3-294" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; &quot;</span> <span class="op">+</span> <span class="st">&quot;-&quot;</span> <span class="op">*</span> <span class="dv">86</span>)</span>
<span id="cb3-295"><a href="#cb3-295" aria-hidden="true" tabindex="-1"></a> plan_billig, _, _ <span class="op">=</span> plane(wind, gleich, abwurfpreis<span class="op">=</span>NIEDRIGER_ABWURFPREIS)</span>
<span id="cb3-296"><a href="#cb3-296" aria-hidden="true" tabindex="-1"></a> billig <span class="op">=</span> zeige(<span class="st">&quot;risikoneutral, billiger Abwurf&quot;</span>, plan_billig, wind,</span>
<span id="cb3-297"><a href="#cb3-297" aria-hidden="true" tabindex="-1"></a> NIEDRIGER_ABWURFPREIS)</span>
<span id="cb3-298"><a href="#cb3-298" aria-hidden="true" tabindex="-1"></a> plan_billig_sicher, _, _ <span class="op">=</span> plane(wind, gleich, cvar_grenze<span class="op">=</span><span class="fl">0.0</span>,</span>
<span id="cb3-299"><a href="#cb3-299" aria-hidden="true" tabindex="-1"></a> abwurfpreis<span class="op">=</span>NIEDRIGER_ABWURFPREIS)</span>
<span id="cb3-300"><a href="#cb3-300" aria-hidden="true" tabindex="-1"></a> billig_sicher <span class="op">=</span> zeige(<span class="st">&quot;+ CVaR 90 </span><span class="sc">% d</span><span class="st">er Fehlmenge = 0&quot;</span>, plan_billig_sicher, wind,</span>
<span id="cb3-301"><a href="#cb3-301" aria-hidden="true" tabindex="-1"></a> NIEDRIGER_ABWURFPREIS)</span>
<span id="cb3-302"><a href="#cb3-302" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-303"><a href="#cb3-303" aria-hidden="true" tabindex="-1"></a> aufpreis <span class="op">=</span> billig_sicher[<span class="st">&quot;mittel&quot;</span>] <span class="op">-</span> billig[<span class="st">&quot;mittel&quot;</span>]</span>
<span id="cb3-304"><a href="#cb3-304" aria-hidden="true" tabindex="-1"></a> vermieden <span class="op">=</span> billig[<span class="st">&quot;fehl_cvar&quot;</span>] <span class="op">-</span> billig_sicher[<span class="st">&quot;fehl_cvar&quot;</span>]</span>
<span id="cb3-305"><a href="#cb3-305" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;</span><span class="ch">\n</span><span class="ss"> Jetzt greift die Schranke: Der risikoneutrale Plan nimmt in&quot;</span>)</span>
<span id="cb3-306"><a href="#cb3-306" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; </span><span class="sc">{</span>billig[<span class="st">&#39;betroffen&#39;</span>]<span class="sc">}</span><span class="ss"> von </span><span class="sc">{</span>SZENARIEN<span class="sc">}</span><span class="ss"> Szenarien einen Lastabwurf in Kauf, weil er bei&quot;</span>)</span>
<span id="cb3-307"><a href="#cb3-307" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; </span><span class="sc">{</span>NIEDRIGER_ABWURFPREIS<span class="sc">:,.0f}</span><span class="ss"> EUR/MWh billiger ist als das Vorhalten eines Blocks.&quot;</span>)</span>
<span id="cb3-308"><a href="#cb3-308" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;</span><span class="ch">\n</span><span class="ss"> Aufpreis fuer die Sicherheit: </span><span class="sc">{</span>aufpreis<span class="sc">:,.0f}</span><span class="ss"> EUR je Tag&quot;</span>)</span>
<span id="cb3-309"><a href="#cb3-309" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> vermieden <span class="op">&gt;</span> <span class="fl">0.01</span>:</span>
<span id="cb3-310"><a href="#cb3-310" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; Vermiedene Fehlmenge (CVaR 90 %): </span><span class="sc">{</span>vermieden<span class="sc">:.1f}</span><span class="ss"> MWh&quot;</span>)</span>
<span id="cb3-311"><a href="#cb3-311" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; -&gt; </span><span class="sc">{</span>aufpreis <span class="op">/</span> vermieden<span class="sc">:,.0f}</span><span class="ss"> EUR je vermiedener MWh&quot;</span>)</span>
<span id="cb3-312"><a href="#cb3-312" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;</span><span class="ch">\n</span><span class="ss"> Diese Zahl ist die Entscheidungsgrundlage - genau wie die Spalte&quot;</span>)</span>
<span id="cb3-313"><a href="#cb3-313" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; &#39;EUR je kg&#39; im Kapitel Mehrziel. Sie sagt der Aufsicht, was ihre&quot;</span>)</span>
<span id="cb3-314"><a href="#cb3-314" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; Versorgungssicherheitsvorgabe tatsaechlich kostet, statt darueber&quot;</span>)</span>
<span id="cb3-315"><a href="#cb3-315" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; zu streiten, wie wichtig sie ist.&quot;</span>)</span>
<span id="cb3-316"><a href="#cb3-316" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-317"><a href="#cb3-317" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;</span><span class="ch">\n</span><span class="st">&quot;</span> <span class="op">+</span> <span class="st">&quot;=&quot;</span> <span class="op">*</span> <span class="dv">88</span>)</span>
<span id="cb3-318"><a href="#cb3-318" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; WAS MAN DARAUS MITNIMMT&quot;</span>)</span>
<span id="cb3-319"><a href="#cb3-319" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;=&quot;</span> <span class="op">*</span> <span class="dv">88</span>)</span>
<span id="cb3-320"><a href="#cb3-320" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;1. Die erste Stufe ist binaer und traege. Was am Vorabend nicht&quot;</span>)</span>
<span id="cb3-321"><a href="#cb3-321" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; angefahren wurde, steht am naechsten Tag nicht zur Verfuegung -&quot;</span>)</span>
<span id="cb3-322"><a href="#cb3-322" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; egal, wie hoch der Preis dann steigt.&quot;</span>)</span>
<span id="cb3-323"><a href="#cb3-323" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;2. Deshalb ist der Erwartungswert als Planungsgrundlage nicht nur&quot;</span>)</span>
<span id="cb3-324"><a href="#cb3-324" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; ungenau, sondern SYSTEMATISCH zu knapp: Er plant fuer einen Tag,&quot;</span>)</span>
<span id="cb3-325"><a href="#cb3-325" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; der so nie eintritt, und laesst keine Reserve fuer die Haelfte&quot;</span>)</span>
<span id="cb3-326"><a href="#cb3-326" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; der Faelle, in denen es schlechter kommt.&quot;</span>)</span>
<span id="cb3-327"><a href="#cb3-327" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;3. Der Ausweg ist keine bessere Windprognose, sondern ein Modell,&quot;</span>)</span>
<span id="cb3-328"><a href="#cb3-328" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; das die Szenarien SIEHT. Die Rechenzeit dafuer liegt hier im&quot;</span>)</span>
<span id="cb3-329"><a href="#cb3-329" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; Sekundenbereich - der Aufwand ist die Modellierung, nicht der&quot;</span>)</span>
<span id="cb3-330"><a href="#cb3-330" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; Solver.&quot;</span>)</span>
<span id="cb3-331"><a href="#cb3-331" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;4. Wo der Lastabwurf teuer genug bepreist ist, deckt schon die&quot;</span>)</span>
<span id="cb3-332"><a href="#cb3-332" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; Minimierung der ERWARTETEN Kosten die Extremfaelle mit ab. Die&quot;</span>)</span>
<span id="cb3-333"><a href="#cb3-333" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; Risikoschranke wird genau dann gebraucht, wenn der Schaden ZU&quot;</span>)</span>
<span id="cb3-334"><a href="#cb3-334" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; NIEDRIG bepreist ist - was bei Versorgungssicherheit die Regel&quot;</span>)</span>
<span id="cb3-335"><a href="#cb3-335" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; ist, weil ein Marktpreisdeckel nicht den volkswirtschaftlichen&quot;</span>)</span>
<span id="cb3-336"><a href="#cb3-336" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; Schaden abbildet. Dann liefert sie den Preis der Vorgabe in Euro&quot;</span>)</span>
<span id="cb3-337"><a href="#cb3-337" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; je vermiedener MWh, und darueber laesst sich verhandeln.&quot;</span>)</span>
<span id="cb3-338"><a href="#cb3-338" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;=&quot;</span> <span class="op">*</span> <span class="dv">88</span>)</span></code></pre></div>
<p><strong>Erwartete Ausgabe</strong> (Laufzeiten hardwareabhängig, die Werte nicht):</p>
<pre><code>========================================================================================
KRAFTWERKSEINSATZ: DER PLAN STEHT, BEVOR DER WIND WEHT
========================================================================================
5 Bloecke, 24 Stunden, 40 Windszenarien (davon 8 Dunkelflauten).
Last 270 bis 804 MW, Wind im Erwartungswert 30 bis 290 MW.
Nicht gedeckte Last kostet 3,000 EUR je MWh.
Planungsgrundlage Kosten Kosten Fehlmenge Fehlmenge Szen. mit
im Mittel schlimmst. Mittel CVaR 90% Abwurf
--------------------------------------------------------------------------------------
nur Wind-Erwartungswert 874,870 2,504,154 178.7 679.2 28/40
alle 40 Szenarien 351,356 415,924 0.0 0.0 0/40
+ Nichtdeckung CVaR 90 % = 0 351,356 415,924 0.0 0.0 0/40
Rechenzeiten: 0.0s / 1.3s / 1.1s (alle beweisbar optimal: True)
----------------------------------------------------------------------------------------
Was der Erwartungswert-Plan anrichtet
Er ist auf dem Papier der billigste - gerechnet auf den mittleren
Wind kostet er weniger als jeder andere. In der Wirklichkeit liegt
er +149% ueber dem zweistufigen Plan, und sein schlimmster Tag
kostet 6.0-mal so viel.
Der Grund steht in der letzten Spalte: In 28 von 40 Szenarien muss
Last abgeworfen werden. Was fehlt, sind nicht Kraftwerke, sondern
ANGEFAHRENE Kraftwerke - und ein Block mit acht Stunden
Mindestlaufzeit laesst sich um 18 Uhr nicht mehr herbeirufen.
Der Unterschied im Plan ist klein:
Erwartungswert 111111122222222211111111 (33 Blockstunden)
zweistufig 111111222222222222222111 (39 Blockstunden)
mit Sicherheit 111111222222222222222111 (39 Blockstunden)
Der zweistufige Plan haelt 6 Blockstunden mehr vor - das genuegt,
um alle 28 Lastabwuerfe zu vermeiden.
----------------------------------------------------------------------------------------
Was Versorgungssicherheit kostet
Bei 3,000 EUR/MWh kostet die CVaR-Schranke NICHTS: Der
risikoneutrale Plan haelt sie schon ein. Das ist kein Zufall - bei
diesem Preis lohnt sich Vorhaltung bereits im Erwartungswert.
Interessant wird die Schranke dort, wo der Schaden ZU NIEDRIG
bepreist ist. Dieselbe Rechnung mit einem Marktpreisdeckel von
300 EUR/MWh statt 3,000:
Planungsgrundlage Kosten Kosten Fehlmenge Fehlmenge Szen. mit
im Mittel schlimmst. Mittel CVaR 90% Abwurf
--------------------------------------------------------------------------------------
risikoneutral, billiger Abwurf 350,512 421,336 3.0 18.4 8/40
+ CVaR 90 % der Fehlmenge = 0 351,356 415,924 0.0 0.0 0/40
Jetzt greift die Schranke: Der risikoneutrale Plan nimmt in
8 von 40 Szenarien einen Lastabwurf in Kauf, weil er bei
300 EUR/MWh billiger ist als das Vorhalten eines Blocks.
Aufpreis fuer die Sicherheit: 844 EUR je Tag
Vermiedene Fehlmenge (CVaR 90 %): 18.4 MWh
-&gt; 46 EUR je vermiedener MWh
Diese Zahl ist die Entscheidungsgrundlage - genau wie die Spalte
&#39;EUR je kg&#39; im Kapitel Mehrziel. Sie sagt der Aufsicht, was ihre
Versorgungssicherheitsvorgabe tatsaechlich kostet, statt darueber
zu streiten, wie wichtig sie ist.
========================================================================================
WAS MAN DARAUS MITNIMMT
========================================================================================
1. Die erste Stufe ist binaer und traege. Was am Vorabend nicht
angefahren wurde, steht am naechsten Tag nicht zur Verfuegung -
egal, wie hoch der Preis dann steigt.
2. Deshalb ist der Erwartungswert als Planungsgrundlage nicht nur
ungenau, sondern SYSTEMATISCH zu knapp: Er plant fuer einen Tag,
der so nie eintritt, und laesst keine Reserve fuer die Haelfte
der Faelle, in denen es schlechter kommt.
3. Der Ausweg ist keine bessere Windprognose, sondern ein Modell,
das die Szenarien SIEHT. Die Rechenzeit dafuer liegt hier im
Sekundenbereich - der Aufwand ist die Modellierung, nicht der
Solver.
4. Wo der Lastabwurf teuer genug bepreist ist, deckt schon die
Minimierung der ERWARTETEN Kosten die Extremfaelle mit ab. Die
Risikoschranke wird genau dann gebraucht, wenn der Schaden ZU
NIEDRIG bepreist ist - was bei Versorgungssicherheit die Regel
ist, weil ein Marktpreisdeckel nicht den volkswirtschaftlichen
Schaden abbildet. Dann liefert sie den Preis der Vorgabe in Euro
je vermiedener MWh, und darueber laesst sich verhandeln.
========================================================================================</code></pre>
<hr />
<h2 id="sec:supplychain-befund">17.5 Der Befund</h2>
<table>
<colgroup>
<col style="width: 20%" />
<col style="width: 26%" />
<col style="width: 26%" />
<col style="width: 26%" />
</colgroup>
<thead>
<tr class="header">
<th>Planungsgrundlage</th>
<th style="text-align: right;">Kosten im Mittel</th>
<th style="text-align: right;">schlimmster Tag</th>
<th style="text-align: right;">Szenarien mit Lastabwurf</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>nur Wind-Erwartungswert</td>
<td style="text-align: right;">874 870 €</td>
<td style="text-align: right;">2 504 154 €</td>
<td style="text-align: right;"><strong>28 von 40</strong></td>
</tr>
<tr class="even">
<td>alle 40 Szenarien</td>
<td style="text-align: right;"><strong>351 356 €</strong></td>
<td style="text-align: right;"><strong>415 924 €</strong></td>
<td style="text-align: right;"><strong>0 von 40</strong></td>
</tr>
</tbody>
</table>
<p>Der Erwartungswert-Plan kostet in der Wirklichkeit <strong>149 % mehr</strong>, und sein schlimmster Tag ist sechsmal so teuer.</p>
<p><strong>Wofür genau?</strong> Die Summendifferenz von 523 514 € sagt noch nicht, wo sie entsteht. Zerlegt man sie nach Kostenarten, wird aus dem Befund eine Aussage, die man vorlegen kann:</p>
<figure>
<img src="bilder_04/kap_supplychain_wirkung.svg" alt="Abb. 17.1: Wofür der Erwartungswert-Plan 149 % mehr bezahlt" />
<figcaption aria-hidden="true">Abb. 17.1: Wofür der Erwartungswert-Plan 149 % mehr bezahlt</figcaption>
</figure>
<p>Drei Dinge stehen darin, die die Tabelle nicht zeigt. Die <strong>Anfahrkosten sind in beiden Plänen gleich</strong> (58 000 €) — der Erwartungswert-Plan spart also nicht dort, wo man es vermuten würde. Er spart <strong>12 725 € Brennstoff</strong>, weil er weniger Blockstunden vorhält. Und er bezahlt dafür <strong>536 239 € Lastabwurf</strong>: das <strong>42-fache</strong> seiner Ersparnis.</p>
<p>Genau diese Gegenüberstellung ist es, die eine Investitionsentscheidung trägt. „149 % mehr” ist eine Zahl, über die man streiten kann; „wir sparen 12 725 € und riskieren dafür 536 239 €” ist eine, über die man entscheidet.</p>
<blockquote>
<p><strong>📌 Zum Diagramm</strong> Es wird von <code>bilder_04/erzeuge_wirkung.py</code> erzeugt, das die Instanz aus <code>Kraftwerkseinsatz.py</code> <strong>erneut rechnet</strong> statt Zahlen zu übernehmen — und dabei die beiden abgedruckten Summen exakt reproduziert. Die Trennung von Brennstoff- und Abwurfkosten ist der einzige Zusatz; das Buchprogramm braucht sie nicht.</p>
</blockquote>
<p>Der Unterschied zwischen den beiden Plänen ist dabei erstaunlich klein:</p>
<pre><code>Erwartungswert 111111122222222211111111 (33 Blockstunden)
zweistufig 111111222222222222222111 (39 Blockstunden)</code></pre>
<p><strong>Sechs zusätzliche Blockstunden verhindern 28 Lastabwürfe.</strong> Der zweistufige Plan fährt den zweiten Block eine Stunde früher an und lässt ihn bis 21 Uhr statt bis 16 Uhr laufen.</p>
<blockquote>
<p><strong>⚠️ Warum der Erwartungswert hier systematisch versagt</strong></p>
<p>Der Fehler ist nicht, dass die Windprognose ungenau wäre. Er liegt in der <strong>Trägheit der ersten Stufe</strong>: Was am Vorabend nicht angefahren wurde, steht am nächsten Tag nicht zur Verfügung — egal, wie hoch der Preis dann steigt.</p>
<p>Eine Planung auf den Mittelwert lässt in der Hälfte der Fälle zu wenig Reserve. Bei einer <em>anpassbaren</em> Größe wäre das halb so schlimm, weil man nachsteuern könnte. Bei einem Kernblock mit acht Stunden Mindestlaufzeit gibt es kein Nachsteuern.</p>
<p>Das ist eine Verschärfung des „Fluchs des Durchschnitts” aus <a href="unsicherheit.html#sec:unsicherheit-der-fluch-des-durchschnitts">Abschnitt 12.3</a>: Dort war der Mittelwert eine schlechte Näherung, hier ist er eine <strong>nicht revidierbare</strong> schlechte Näherung.</p>
</blockquote>
<hr />
<h2 id="sec:supplychain-sicherheit">17.6 Was Versorgungssicherheit kostet</h2>
<p>Der dritte Plan legt eine CVaR-Schranke auf die nicht gedeckte Energie: Im Mittel der schlechtesten 10 % der Szenarien darf <strong>nichts</strong> fehlen. Dieselbe Rockafellar-Uryasev-Konstruktion wie in <a href="cvar.html#kap-cvar">Kapitel 20</a>, nur dass hier Megawattstunden begrenzt werden statt Euro.</p>
<p>Das Ergebnis ist zunächst enttäuschend — und dann lehrreich:</p>
<table>
<colgroup>
<col style="width: 20%" />
<col style="width: 26%" />
<col style="width: 26%" />
<col style="width: 26%" />
</colgroup>
<thead>
<tr class="header">
<th>Abwurfpreis</th>
<th style="text-align: right;">risikoneutral</th>
<th style="text-align: right;">mit CVaR-Schranke</th>
<th style="text-align: right;">Aufpreis</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>3 000 €/MWh</td>
<td style="text-align: right;">351 356 €, kein Abwurf</td>
<td style="text-align: right;">351 356 €, kein Abwurf</td>
<td style="text-align: right;"><strong>0 €</strong></td>
</tr>
<tr class="even">
<td>300 €/MWh</td>
<td style="text-align: right;">350 512 €, Abwurf in 8/40</td>
<td style="text-align: right;">351 356 €, kein Abwurf</td>
<td style="text-align: right;"><strong>844 €</strong></td>
</tr>
</tbody>
</table>
<p>Bei 3 000 €/MWh kostet die Schranke <strong>nichts</strong>: Der risikoneutrale Plan hält sie längst ein. Bei diesem Preis lohnt sich das Vorhalten eines Blocks schon im Erwartungswert, lange bevor jemand über Risiko spricht.</p>
<p>Erst bei einem Marktpreisdeckel von 300 €/MWh greift sie. Dann nimmt der risikoneutrale Plan in 8 von 40 Szenarien einen Lastabwurf in Kauf, weil er billiger ist als Vorhaltung — und die Schranke kostet 844 € je Tag für 18,4 vermiedene MWh im CVaR:</p>
<p><span class="math display">
\frac{844\ \text{€}}{18{,}4\ \text{MWh}} \approx 46\ \text{€ je vermiedener MWh}
</span></p>
<blockquote>
<p><strong>🎯 Merksatz</strong> Eine Risikoschranke ändert genau dann etwas, wenn der Schaden <strong>zu niedrig bepreist</strong> ist. Ist er realistisch bewertet, erledigt die Minimierung der erwarteten Kosten die Absicherung von selbst.</p>
</blockquote>
<p>Das ist keine akademische Feinheit, sondern die reale Lage der Energiewirtschaft: Ein Marktpreisdeckel bildet den volkswirtschaftlichen Schaden eines Stromausfalls nicht ab. Genau deshalb gibt es regulatorische Vorgaben zur Versorgungssicherheit — und diese Zahl, 46 € je vermiedener MWh, ist das, worüber sich verhandeln lässt. Sie ist dasselbe Instrument wie die Spalte „€ je kg” in <a href="mehrziel.html#sec:mehrziel-vorlegen">Abschnitt 14.8</a>.</p>
<hr />
<h2 id="sec:supplychain-uebungsaufgaben">17.7 Übungsaufgaben</h2>
<blockquote>
<p>Lösungen: <a href="anhang-loesungen.html#sec:loesungen-supplychain">Abschnitt A.17</a>.</p>
</blockquote>
<p><strong>Aufgabe 17.1 ⭐ — Der Umschlagpunkt.</strong> Rechnen Sie den Umschlagpunkt aus dem Schnellstart für eine Leistung von 60 MW statt 120 MW nach. In welche Richtung verschiebt er sich, und warum ist das plausibel?</p>
<p><strong>Aufgabe 17.2 ⭐ — Die fehlende Nebenbedingung.</strong> Das Modell kennt Mindestlaufzeiten, aber keine <strong>Mindeststillstandszeiten</strong>. Formulieren Sie die entsprechende Bedingung. Welchen realen Sachverhalt bildet sie ab?</p>
<p><strong>Aufgabe 17.3 ⭐⭐ — Wie viele Szenarien?</strong> Rechnen Sie mit 10, 20, 40 und 80 Szenarien. Ab wann ändert sich der Commitment-Plan nicht mehr? Was folgt daraus für die Praxis — und was hat das mit <a href="prognose.html#sec:prognose-messfalle">Abschnitt 15.6</a> zu tun?</p>
<p><strong>Aufgabe 17.4 ⭐⭐ — Der Wert eines Speichers.</strong> Ergänzen Sie einen Batteriespeicher (100 MW, 400 MWh, Wirkungsgrad 90 %). Um wie viel sinken die erwarteten Kosten — und was ist der Speicher damit je MWh Kapazität wert?</p>
<p><strong>Aufgabe 17.5 ⭐⭐⭐ — Wenn es größer wird.</strong> Erhöhen Sie auf 20 Blöcke und 168 Stunden (eine Woche). Beobachten Sie MIP-Gap und Rechenzeit (<a href="milp.html#sec:milp-gap">Abschnitt 6.8</a>). Ab wann wird das Problem für den exakten Solver zu groß — und welches Verfahren aus <a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a> würden Sie einsetzen?</p>
<hr />
<h2 id="sec:supplychain-denkfehler">17.8 Finde den Denkfehler</h2>
<div class="card card-denkfehler">
<blockquote>
<p><strong>🐛 „Wir rechnen mit dem P50-Szenario”</strong></p>
<p>Ein Netzbetreiber beschreibt sein Vorgehen:</p>
<blockquote>
<p><em>„Wir verwenden für die Tagesplanung das <strong>P50-Szenario</strong> der Windprognose — also den &gt; Median. Die Hälfte der Tage fällt besser aus, die Hälfte schlechter, im Mittel gleicht &gt; sich das aus. Für die Extremfälle haben wir zusätzlich eine Reserve von 5 % der Last &gt; vorgehalten, das ist die branchenübliche Größenordnung.”</em></p>
</blockquote>
<p>Das klingt sorgfältig, und beides ist gängige Praxis.</p>
<p><strong>Beide Teile der Aussage enthalten einen Fehler. Welche?</strong></p>
<p>Ein Hinweis zum zweiten Teil: Sehen Sie sich in der Ausgabe des Programms an, <em>welche</em> Größe der Plan verändert hat, um die Lastabwürfe zu vermeiden — und vergleichen Sie das mit dem, was eine prozentuale Leistungsreserve leisten kann.</p>
</blockquote>
</div>
<hr />
<h2 id="sec:supplychain-quiz">17.9 Micro-Quiz</h2>
<div class="card card-quiz">
<blockquote>
<p><strong>❓ Drei Fragen</strong></p>
<p><strong>1. Warum ist die Merit-Order-Regel („billigstes Kraftwerk zuerst”) für die Tagesplanung nicht ausreichend?</strong> a) Weil sie die Netzverluste ignoriert. b) Weil Anfahrkosten und Mindestlaufzeiten die Stunden miteinander koppeln — die Entscheidung einer Stunde bindet die folgenden. c) Weil Grenzkosten in der Praxis nicht bekannt sind.</p>
<p><strong>2. Was unterscheidet dieses zweistufige Modell von dem in <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a>?</strong> a) Es hat mehr Szenarien. b) Die erste Stufe ist <strong>binär</strong> und damit nicht anteilig anpassbar. c) Es minimiert den CVaR statt des Erwartungswerts.</p>
<p><strong>3. Bei 3 000 €/MWh kostet die CVaR-Schranke nichts, bei 300 €/MWh dagegen 844 €/Tag. Warum?</strong> a) Weil der Solver bei kleineren Zahlen ungenauer rechnet. b) Weil bei realistisch hohem Abwurfpreis schon die Minimierung der erwarteten Kosten Vorhaltung erzwingt; die Schranke greift nur, wenn der Schaden zu niedrig bepreist ist. c) Weil die CVaR-Schranke bei hohen Preisen numerisch unwirksam wird.</p>
</blockquote>
</div>
<hr />
<h2 id="sec:supplychain-selbsttest">17.10 Selbsttest</h2>
<ol type="1">
<li>Erklären Sie in zwei Sätzen, warum ein Kraftwerkspark nicht wie ein Regal aufgefüllt werden kann.</li>
<li>Welche Größe ist in diesem Modell die „here and now”-Entscheidung, welche die „wait and see”-Entscheidung?</li>
<li>Warum ist eine Planung auf den Erwartungswert hier <em>systematisch</em> zu knapp und nicht nur ungenau?</li>
<li>Wann ändert eine Risikoschranke etwas an der Lösung — und wann nicht?</li>
<li>Sie sollen einer Regulierungsbehörde erklären, was ihre Versorgungssicherheitsvorgabe kostet. Welche Zahl nennen Sie, und wie ist sie entstanden?</li>
</ol>
<hr />
<h2 id="sec:supplychain-zusammenfassung">17.11 Zusammenfassung</h2>
<ul>
<li><strong>Anfahrkosten und Mindestlaufzeiten</strong> machen aus 24 Stundenentscheidungen ein einziges Problem. Die Merit-Order gilt nur für einen einzelnen Zeitpunkt; im Schnellstart schlägt die fünfmal teurere Gasturbine den Kernblock bis knapp vier Stunden.</li>
<li>Das Modell ist zweistufig mit <strong>binärer erster Stufe</strong>: Das An/Aus steht am Vorabend fest und gilt für alle Szenarien, die Fahrweise passt sich an. Das ist eine Verschärfung gegenüber <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a>, wo die erste Stufe kontinuierlich war.</li>
<li>Eine Planung auf den <strong>Wind-Erwartungswert</strong> kostet hier 149 % mehr und führt in 28 von 40 Szenarien zum Lastabwurf. Der Grund ist nicht die Prognosegüte, sondern die Trägheit: Was nicht angefahren wurde, ist nicht verfügbar.</li>
<li>Der zweistufige Plan braucht dafür nur <strong>sechs zusätzliche Blockstunden</strong>.</li>
<li>Eine <strong>CVaR-Schranke</strong> auf die nicht gedeckte Energie ändert nur dann etwas, wenn der Schaden zu niedrig bepreist ist. Bei realistischen 3 000 €/MWh erledigt die Minimierung der erwarteten Kosten die Absicherung von selbst.</li>
<li>Wo sie greift, liefert sie den <strong>Preis der Vorgabe</strong>: 46 € je vermiedener MWh — eine Zahl, über die man verhandeln kann.</li>
</ul>
</article>
<button type="button" class="fortschritt-knopf" data-kapitel="supplychain.html"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg> <span>Als gelesen markieren</span></button>
<nav class="prev-next"><a class="prev-next-knopf prev-next-prev" href="bruecke.html"><svg class="icon" aria-hidden="true"><use href="#icon-chevron-left"></use></svg><span><small>Zurück</small>Kapitel 16: Die Strukturbrücke — dieselbe Mathematik, zwei Welten</span></a><a class="prev-next-knopf prev-next-next" href="finanzdaten.html"><span><small>Weiter</small>Kapitel 18: Finanzdaten-Modellierung — Renditen, Kovarianz und Shrinkage</span><svg class="icon" aria-hidden="true"><use href="#icon-chevron-right"></use></svg></a></nav>
</main>
</div>
<footer class="site-footer">
<p>© Dieter Schlüter · <a href="gesamtdokument.html">Gesamtdokument</a> ·
<a href="programme.html">Beispielprogramme</a></p>
</footer>
<script defer src="assets/search-index.js"></script>
<script defer src="assets/programme.js"></script>
<script defer src="assets/site.js"></script>
</body>
</html>