diff --git a/.github/workflows/test-binder-environment.yml b/.github/workflows/test-binder-environment.yml index 457dc39..1cb912a 100644 --- a/.github/workflows/test-binder-environment.yml +++ b/.github/workflows/test-binder-environment.yml @@ -12,6 +12,7 @@ on: - 'postBuild' - '.gitmodules' - '.dockerignore' + - 'notebooks/**' - '.github/workflows/test-binder-environment.yml' push: branches: @@ -21,6 +22,7 @@ on: - 'postBuild' - '.gitmodules' - '.dockerignore' + - 'notebooks/**' - '.github/workflows/test-binder-environment.yml' jobs: @@ -48,14 +50,19 @@ jobs: run: | jupyter-repo2docker --no-run --image-name opentepes-tutorial:ci . - - name: Run the demo notebook inside the built image + - name: Run the tutorial notebooks inside the built image run: | + # Execute the notebooks in the built image so a notebook that no longer + # runs is caught. 1.3 and 3.1 are left out for now (3.1 writes back into + # the case folder and runs a clustering step); they need their own rework. jupyter-repo2docker --image-name opentepes-tutorial:ci . \ - jupyter nbconvert --to notebook --execute \ - --ExecutePreprocessor.timeout=600 \ - --output /tmp/executed-demo.ipynb \ - notebooks/01-openTEPES-Demo.ipynb + bash -lc 'jupyter nbconvert --to notebook --execute \ + --ExecutePreprocessor.timeout=900 --output-dir /tmp/executed \ + notebooks/0*.ipynb \ + notebooks/2.1-Comparison.ipynb \ + notebooks/4.*.ipynb \ + notebooks/5.*.ipynb' - name: Summary if: success() - run: echo "Binder image built with repo2docker and the demo notebook ran successfully." + run: echo "Binder image built with repo2docker and the tutorial notebooks ran successfully." diff --git a/notebooks/02-Time-Step.ipynb b/notebooks/02-Time-Step.ipynb index f136b89..8ab0bc1 100644 --- a/notebooks/02-Time-Step.ipynb +++ b/notebooks/02-Time-Step.ipynb @@ -2,91 +2,303 @@ "cells": [ { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "id": "682e17b6", + "metadata": {}, "source": [ "# Time-Step: hourly, bi-hourly, tri-hourly, etc.\n", - "This notebook presents an example of the openTEPES' features: Time-Step. This feature controls the time domain's resolution, either hourly or bi-hourly, etc.\n", - "The main point is that if Time-Step is not equal to 1, openTEPES computes the demand as the mean over the time step load levels and assign it to active load levels. Idem for operating reserve, variable max power, variable min, and max storage and inflows. For example, we perfom the next comparison." + "\n", + "The `TimeStep` parameter sets the time resolution of the model. `1` is hourly, `2` bi-hourly, `4` tetra-hourly, and so on. When `TimeStep` is greater than 1, openTEPES averages the demand (and the other time series) over each block, so the model has fewer load levels and solves faster, at the cost of detail.\n", + "\n", + "To keep every run quick, we use a one-week slice of the 9-node case." ] }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "id": "a6c36b68", + "metadata": {}, "source": [ - "## Changing TimeStep equal to 3" + "## Set up a one-week working copy" ] }, { "cell_type": "code", "execution_count": 1, + "id": "34fd9c7e", "metadata": { - "pycharm": { - "name": "#%%\n" + "execution": { + "iopub.execute_input": "2026-06-29T19:58:12.852814Z", + "iopub.status.busy": "2026-06-29T19:58:12.852399Z", + "iopub.status.idle": "2026-06-29T19:58:13.324254Z", + "shell.execute_reply": "2026-06-29T19:58:13.323829Z" } }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "One-week working copy ready.\n" + ] + } + ], "source": [ - "import altair as alt\n", + "import os, shutil\n", "import pandas as pd\n", - "from openTEPES.openTEPES import openTEPES_run" + "import altair as alt\n", + "from openTEPES.openTEPES import openTEPES_run\n", + "\n", + "DIR = \"work_TimeStep\"\n", + "CaseName = \"9n\"\n", + "\n", + "if os.path.exists(DIR):\n", + " shutil.rmtree(DIR)\n", + "shutil.copytree(CaseName, os.path.join(DIR, CaseName))\n", + "\n", + "# Keep only the first week (168 hours); drop the rest by clearing their duration.\n", + "dur_path = os.path.join(DIR, CaseName, \"oT_Data_Duration_9n.csv\")\n", + "dur = pd.read_csv(dur_path)\n", + "dur[\"Duration\"] = dur[\"Duration\"].astype(float)\n", + "dur.loc[168:, \"Duration\"] = float(\"nan\")\n", + "dur.to_csv(dur_path, index=False)\n", + "\n", + "# The annual renewable-energy requirement is sized for a full year, so it\n", + "# would exceed a single week's demand. Clear it for this short horizon.\n", + "res_path = os.path.join(DIR, CaseName, \"oT_Data_RESEnergy_9n.csv\")\n", + "res = pd.read_csv(res_path)\n", + "res[\"RESEnergy\"] = float(\"nan\")\n", + "res.to_csv(res_path, index=False)\n", + "print(\"One-week working copy ready.\")" ] }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "id": "8568dc6f", + "metadata": {}, "source": [ - "### Defining the DirName, CaseName, SolverName, and IndLogConsole." + "## A helper to solve at a chosen time step\n", + "\n", + "It sets `TimeStep` in the working copy, solves, and returns the total energy per technology over the week (the generation per load level summed and multiplied by the time step, so the totals are comparable across resolutions)." ] }, { "cell_type": "code", "execution_count": 2, + "id": "ed97c214", "metadata": { - "pycharm": { - "name": "#%%\n" + "execution": { + "iopub.execute_input": "2026-06-29T19:58:13.325378Z", + "iopub.status.busy": "2026-06-29T19:58:13.325310Z", + "iopub.status.idle": "2026-06-29T19:58:13.327491Z", + "shell.execute_reply": "2026-06-29T19:58:13.327207Z" } }, "outputs": [], "source": [ - "DirName =''\n", - "CaseName = '9n'\n", - "SolverName = 'glpk'\n", - "IndOutputResults = 'Yes'\n", - "IndLogConsole = 'No'" + "def solve_at(time_step, tag):\n", + " p = os.path.join(DIR, CaseName, \"oT_Data_Parameter_9n.csv\")\n", + " df = pd.read_csv(p)\n", + " df.loc[:, \"TimeStep\"] = time_step\n", + " df.to_csv(p, index=False)\n", + " openTEPES_run(DIR, CaseName, \"appsi_highs\", \"Yes\", \"No\")\n", + " out = pd.read_csv(os.path.join(DIR, CaseName, \"oT_Result_TechnologyGeneration_9n.csv\"))\n", + " tech = [c for c in out.columns if c not in (\"Scenario\", \"Period\", \"LoadLevel\")]\n", + " energy = (out[tech].sum() * time_step / 1000).rename(\"GWh\").reset_index()\n", + " energy = energy.rename(columns={\"index\": \"Technology\"})\n", + " energy[\"Resolution\"] = tag\n", + " return energy" ] }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "id": "bceb1b4b", + "metadata": {}, "source": [ - "In the folder called ``9n``, you can find the CSV file ``oT_Data_Parameter_9n`` which is also shown as follows:" + "## Hourly vs tetra-hourly\n", + "\n", + "We solve the same week at hourly resolution (`TimeStep = 1`, 168 load levels) and at tetra-hourly resolution (`TimeStep = 4`, 42 load levels), then compare the total energy per technology. The totals stay close, which is why a coarser resolution is a good, faster approximation." ] }, { "cell_type": "code", "execution_count": 3, + "id": "50e5d947", "metadata": { - "pycharm": { - "name": "#%%\n" + "execution": { + "iopub.execute_input": "2026-06-29T19:58:13.328486Z", + "iopub.status.busy": "2026-06-29T19:58:13.328427Z", + "iopub.status.idle": "2026-06-29T19:58:17.068891Z", + "shell.execute_reply": "2026-06-29T19:58:17.068548Z" } }, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Input data ****\n", + "Reading the CSV files ... 0 s\n", + "Reading input data ... 0 s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Setting up input data ... 0 s\n", + "Setting up variables ... 0 s\n", + "Total cost o.f. model formulation ****\n", + "Investment elec model formulation ****\n", + "Period 2030, Scenario sc01, Stage st1\n", + "Generation oper o.f. model formulation ****\n", + "Investment & operation var constraints ****\n", + "Inertia, oper resr, demand constraints ****\n", + "Storage scheduling constraints ****\n", + "Unit commitment constraints ****\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ramp and min up/down time constraints ****\n", + "Network switching model constraints ****\n", + "Network operation model constraints ****\n", + "Problem solving #### 1\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Termination condition: optimal\n", + " Total system cost [MEUR] 5.526395235179494 Constraints 18987 Variables 23442 Seconds 1\n", + "***** Period: 2030, Scenario: sc01, Stage: st1 ******\n", + " Total generation investment cost [MEUR] 0\n", + " Total generation retirement cost [MEUR] 0\n", + " Total reservoir investment cost [MEUR] 0.0\n", + " Total network investment cost [MEUR] 0.0\n", + " Total H2 pipe investment cost [MEUR] 0.0\n", + " Total heat pipe investment cost [MEUR] 0.0\n", + " Total generation operation cost [MEUR] 5.526359640517674\n", + " Total consumption operation cost [MEUR] 5.683115002813704e-07\n", + " Total emission cost [MEUR] 0.0\n", + " Total network losses penalty cost [MEUR] 3.502635032421968e-05\n", + " Total reliability electr cost [MEUR] 0.0\n", + "Writing investment results ... 0 s\n", + "Writing cost summary results ... 0 s\n", + "Writing KPI summary results ... 0 s\n", + "Writing elect network summary results ... 0 s\n", + "Writing reliability indexes ... 0 s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing flexibility results ... 0 s\n", + "Writing generation operation results ... 0 s\n", + "Writing ESS operation results ... 0 s\n", + "Writing elect netwk operation results ... 0 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/private/tmp/claude-501/-Users-philias-ai-research-repos-openTEPES-tutorial/8f6d4ac5-9ff1-45bc-8a3c-5cc562abe3f1/scratchpad/venv312/lib/python3.12/site-packages/altair/utils/core.py:264: UserWarning: I don't know how to infer vegalite type from 'empty'. Defaulting to nominal.\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing marginal information results ... 0 s\n", + "Writing economic results ... 0 s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Plotting electricity network maps ... 0 s\n", + "Input data ****\n", + "Reading the CSV files ... 0 s\n", + "Reading input data ... 0 s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Setting up input data ... 0 s\n", + "Setting up variables ... 0 s\n", + "Total cost o.f. model formulation ****\n", + "Investment elec model formulation ****\n", + "Period 2030, Scenario sc01, Stage st1\n", + "Generation oper o.f. model formulation ****\n", + "Investment & operation var constraints ****\n", + "Inertia, oper resr, demand constraints ****\n", + "Storage scheduling constraints ****\n", + "Unit commitment constraints ****\n", + "Ramp and min up/down time constraints ****\n", + "Network switching model constraints ****\n", + "Network operation model constraints ****\n", + "Problem solving #### 1\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Termination condition: optimal\n", + " Total system cost [MEUR] 5.501981377951612 Constraints 4749 Variables 5865 Seconds 0\n", + "***** Period: 2030, Scenario: sc01, Stage: st1 ******\n", + " Total generation investment cost [MEUR] 0\n", + " Total generation retirement cost [MEUR] 0\n", + " Total reservoir investment cost [MEUR] 0.0\n", + " Total network investment cost [MEUR] 0.0\n", + " Total H2 pipe investment cost [MEUR] 0.0\n", + " Total heat pipe investment cost [MEUR] 0.0\n", + " Total generation operation cost [MEUR] 5.501944928226971\n", + " Total consumption operation cost [MEUR] 1.4685590239468652e-06\n", + " Total emission cost [MEUR] 0.0\n", + " Total network losses penalty cost [MEUR] 3.4981165616163933e-05\n", + " Total reliability electr cost [MEUR] 0.0\n", + "Writing investment results ... 0 s\n", + "Writing cost summary results ... 0 s\n", + "Writing KPI summary results ... 0 s\n", + "Writing elect network summary results ... 0 s\n", + "Writing reliability indexes ... 0 s\n", + "Writing flexibility results ... 0 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/private/tmp/claude-501/-Users-philias-ai-research-repos-openTEPES-tutorial/8f6d4ac5-9ff1-45bc-8a3c-5cc562abe3f1/scratchpad/venv312/lib/python3.12/site-packages/altair/utils/core.py:264: UserWarning: I don't know how to infer vegalite type from 'empty'. Defaulting to nominal.\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing generation operation results ... 0 s\n", + "Writing ESS operation results ... 0 s\n", + "Writing elect netwk operation results ... 0 s\n", + "Writing marginal information results ... 0 s\n", + "Writing economic results ... 0 s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Plotting electricity network maps ... 0 s\n" + ] + }, { "data": { "text/html": [ @@ -108,40 +320,102 @@ " \n", " \n", " \n", - " ENSCost\n", - " CO2Cost\n", - " UpReserveActivation\n", - " DwReserveActivation\n", - " MinRatioDwUp\n", - " MaxRatioDwUp\n", - " SBase\n", - " ReferenceNode\n", - " TimeStep\n", + " Technology\n", + " GWh\n", + " Resolution\n", " \n", " \n", " \n", " \n", - " Parameters\n", - " 10000\n", - " 25\n", - " 0.25\n", - " 0.3\n", - " 0\n", - " 1\n", - " 100\n", - " Node_4\n", - " 1\n", + " 0\n", + " Coal\n", + " 0.00\n", + " hourly (TimeStep 1)\n", + " \n", + " \n", + " 1\n", + " ESS\n", + " 0.05\n", + " hourly (TimeStep 1)\n", + " \n", + " \n", + " 2\n", + " Gas\n", + " 71.62\n", + " hourly (TimeStep 1)\n", + " \n", + " \n", + " 3\n", + " Nuclear\n", + " 113.88\n", + " hourly (TimeStep 1)\n", + " \n", + " \n", + " 4\n", + " Oil\n", + " 0.00\n", + " hourly (TimeStep 1)\n", + " \n", + " \n", + " 5\n", + " RES\n", + " 13.90\n", + " hourly (TimeStep 1)\n", + " \n", + " \n", + " 0\n", + " Coal\n", + " 0.00\n", + " tetra-hourly (TimeStep 4)\n", + " \n", + " \n", + " 1\n", + " ESS\n", + " 0.13\n", + " tetra-hourly (TimeStep 4)\n", + " \n", + " \n", + " 2\n", + " Gas\n", + " 71.60\n", + " tetra-hourly (TimeStep 4)\n", + " \n", + " \n", + " 3\n", + " Nuclear\n", + " 113.90\n", + " tetra-hourly (TimeStep 4)\n", + " \n", + " \n", + " 4\n", + " Oil\n", + " 0.00\n", + " tetra-hourly (TimeStep 4)\n", + " \n", + " \n", + " 5\n", + " RES\n", + " 13.90\n", + " tetra-hourly (TimeStep 4)\n", " \n", " \n", "\n", "" ], "text/plain": [ - " ENSCost CO2Cost UpReserveActivation DwReserveActivation \\\n", - "Parameters 10000 25 0.25 0.3 \n", - "\n", - " MinRatioDwUp MaxRatioDwUp SBase ReferenceNode TimeStep \n", - "Parameters 0 1 100 Node_4 1 " + " Technology GWh Resolution\n", + "0 Coal 0.00 hourly (TimeStep 1)\n", + "1 ESS 0.05 hourly (TimeStep 1)\n", + "2 Gas 71.62 hourly (TimeStep 1)\n", + "3 Nuclear 113.88 hourly (TimeStep 1)\n", + "4 Oil 0.00 hourly (TimeStep 1)\n", + "5 RES 13.90 hourly (TimeStep 1)\n", + "0 Coal 0.00 tetra-hourly (TimeStep 4)\n", + "1 ESS 0.13 tetra-hourly (TimeStep 4)\n", + "2 Gas 71.60 tetra-hourly (TimeStep 4)\n", + "3 Nuclear 113.90 tetra-hourly (TimeStep 4)\n", + "4 Oil 0.00 tetra-hourly (TimeStep 4)\n", + "5 RES 13.90 tetra-hourly (TimeStep 4)" ] }, "execution_count": 3, @@ -150,233 +424,23 @@ } ], "source": [ - "df = pd.read_csv(CaseName+'/oT_Data_Parameter_'+CaseName+'.csv', index_col=[0])\n", - "df.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "This CSV file comprises all the system parameters of the openTEPES mode. It has a column called TimeStep, that having ``1`` for hourly resolution, ``2`` for bi-hourly resolution, etc. In our example, we consider a TimeStep equal to ``3`` (tri-hourly resolution) and equal to ``4`` (tetra-hourly resolution)." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "### Having tri-hourly resolution" + "hourly = solve_at(1, \"hourly (TimeStep 1)\")\n", + "tetra = solve_at(4, \"tetra-hourly (TimeStep 4)\")\n", + "comparison = pd.concat([hourly, tetra])\n", + "comparison[\"GWh\"] = comparison[\"GWh\"].round(2)\n", + "comparison" ] }, { "cell_type": "code", "execution_count": 4, + "id": "e334a97c", "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [], - "source": [ - "df['TimeStep'] = 3" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [], - "source": [ - "df.to_csv(CaseName+'/oT_Data_Parameter_'+CaseName+'.csv', index=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Input data ****\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Users\\erik_\\miniconda3\\lib\\site-packages\\pandas\\core\\frame.py:5176: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " return super().fillna(\n", - "C:\\Users\\erik_\\miniconda3\\lib\\site-packages\\pyomo\\core\\base\\block.py:541: PerformanceWarning: indexing past lexsort depth may impact performance.\n", - " self.add_component(name, val)\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Reading input data ... 0 s\n", - "Setting up input data ... 20 s\n", - "Setting up variables ... 8 s\n", - "Investment model formulation ****\n", - "Generation operation model formulation ****\n", - "Network switching model formulation ****\n", - "Network operation model formulation ****\n", - "Writing LP file ... 60 s\n", - "Problem solving ****\n", - "# ==========================================================\n", - "# = Solver Results =\n", - "# ==========================================================\n", - "# ----------------------------------------------------------\n", - "# Problem Information\n", - "# ----------------------------------------------------------\n", - "Problem: \n", - "- Name: x1712273\n", - " Lower bound: 136.41411098938326\n", - " Upper bound: 136.41411098938326\n", - " Number of objectives: 1\n", - " Number of constraints: 899782\n", - " Number of variables: 1108851\n", - " Number of binary variables: 0\n", - " Number of integer variables: 0\n", - " Number of continuous variables: 1108851\n", - " Number of nonzeros: 3737808\n", - " Sense: minimize\n", - "# ----------------------------------------------------------\n", - "# Solver Information\n", - "# ----------------------------------------------------------\n", - "Solver: \n", - "- Status: ok\n", - " Return code: 0\n", - " Message: Model was solved to optimality (subject to tolerances), and an optimal solution is available.\n", - " Termination condition: optimal\n", - " Termination message: Model was solved to optimality (subject to tolerances), and an optimal solution is available.\n", - " Wall time: 47.00091743469238\n", - " Error rc: 0\n", - " Time: 60.78045320510864\n", - "# ----------------------------------------------------------\n", - "# Solution Information\n", - "# ----------------------------------------------------------\n", - "Solution: \n", - "- number of solutions: 0\n", - " number of solutions displayed: 0\n", - "Solution time ... 117 s\n", - "Total system cost [MEUR] 136.41411098938107\n", - "Total investment cost [MEUR] 4.543914175410445\n", - "Total generation cost [MEUR] 131.87019681397064\n", - "Total consumption cost [MEUR] 0.0\n", - "Total emission cost [MEUR] 0.0\n", - "Total reliability cost [MEUR] 0.0\n", - "Writing investment results ... 0 s\n", - "Writing generation operation results ... 23 s\n", - "Writing ESS operation results ... 2 s\n", - "Writing flexibility results ... 4 s\n", - "Writing network operation results ... 4 s\n", - "Writing marginal information results ... 5 s\n", - "Writing economic results ... 13 s\n", - "Plotting network maps ... 1 s\n", - "Total time ... 307 s\n" - ] - } - ], - "source": [ - "model_TS1 = openTEPES_run(DirName, CaseName, SolverName, IndOutputResults, IndLogConsole)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "### Getting the total output per technology" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [], - "source": [ - "OutputToFile_TS1 = pd.Series(data=[sum(model_TS1.vTotalOutput[sc,p,n,g]() for g in model_TS1.g if (gt,g) in model_TS1.t2g)*model_TS1.pTimeStep() for sc,p,n,gt in model_TS1.sc*model_TS1.p*model_TS1.n*model_TS1.gt], index=pd.MultiIndex.from_tuples(model_TS1.sc*model_TS1.p*model_TS1.n*model_TS1.gt))\n", - "OutputToFile_TS1 = OutputToFile_TS1.to_frame(name='GW' ).reset_index().pivot_table(index=['level_0','level_1','level_2'], columns='level_3', values='GW').rename_axis(['Scenario','Period','LoadLevel'], axis=0).rename_axis([None], axis=1).sum(axis=0)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [], - "source": [ - "OutputToFile_TS1.index.names = ['Technology']\n", - "OutputToFile_TS1 = OutputToFile_TS1.to_frame(name='GWh')\n", - "OutputToFile_TS1['Resolution'] = 'TimeStep-3'\n", - "OutputToFile_TS1 = OutputToFile_TS1.reset_index()" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [], - "source": [ - "OutputToFile_TS1['GWh'] = round(OutputToFile_TS1['GWh'], 2)" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [], - "source": [ - "chart = alt.Chart(OutputToFile_TS1).mark_bar().encode(x='Technology:N', y='GWh:Q', color='Technology:N', column='Resolution:O')\n", - "# chart.save(CaseName+'/oT_Plot_TechnologyOutputComparison_'+CaseName+'.html', embed_options={'renderer':'svg'})" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "pycharm": { - "name": "#%%\n" + "execution": { + "iopub.execute_input": "2026-06-29T19:58:17.069841Z", + "iopub.status.busy": "2026-06-29T19:58:17.069781Z", + "iopub.status.idle": "2026-06-29T19:58:17.076952Z", + "shell.execute_reply": "2026-06-29T19:58:17.076612Z" } }, "outputs": [ @@ -384,19 +448,31 @@ "data": { "text/html": [ "\n", - "
\n", + "\n", + "
\n", "" ], "text/plain": [ "alt.Chart(...)" ] }, - "execution_count": 11, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "chart" + "alt.Chart(comparison).mark_bar().encode(\n", + " x=\"Resolution:O\", y=\"GWh:Q\", color=\"Resolution:O\", column=\"Technology:N\"\n", + ").properties(width=80)" ] }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "## Comparison of the total output per technology considering TimeStep equal to 3 and 4\n", - "An additional example can be found in the following notebook:" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "id": "c2bbf94b", + "metadata": {}, "source": [ - "- [2.1-Comparison.ipynb](2.1-Comparison.ipynb)" + "For a comparison on the full year at two coarser resolutions, see [2.1-Comparison.ipynb](2.1-Comparison.ipynb)." ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -492,9 +556,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.5" + "version": "3.12.13" } }, "nbformat": 4, - "nbformat_minor": 1 + "nbformat_minor": 5 } diff --git a/notebooks/5.1-Sweep-Mode-A-PreBuild.ipynb b/notebooks/5.1-Sweep-Mode-A-PreBuild.ipynb index ba7c055..8093197 100644 --- a/notebooks/5.1-Sweep-Mode-A-PreBuild.ipynb +++ b/notebooks/5.1-Sweep-Mode-A-PreBuild.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "3a243cc3", + "id": "b8773c2d", "metadata": {}, "source": [ "# Sweep Mode A — Pre-build sweep\n", @@ -18,7 +18,7 @@ }, { "cell_type": "markdown", - "id": "364eb3f8", + "id": "f782a9da", "metadata": {}, "source": [ "## The question\n", @@ -31,13 +31,13 @@ { "cell_type": "code", "execution_count": 1, - "id": "292b3e8d", + "id": "b6534d91", "metadata": { "execution": { - "iopub.execute_input": "2026-06-29T19:35:49.539307Z", - "iopub.status.busy": "2026-06-29T19:35:49.539042Z", - "iopub.status.idle": "2026-06-29T19:35:49.824392Z", - "shell.execute_reply": "2026-06-29T19:35:49.824032Z" + "iopub.execute_input": "2026-06-29T19:55:03.580715Z", + "iopub.status.busy": "2026-06-29T19:55:03.580383Z", + "iopub.status.idle": "2026-06-29T19:55:03.879197Z", + "shell.execute_reply": "2026-06-29T19:55:03.878779Z" } }, "outputs": [ @@ -78,7 +78,7 @@ }, { "cell_type": "markdown", - "id": "a8ff8bfd", + "id": "381a37db", "metadata": {}, "source": [ "## Run the sweep\n", @@ -91,13 +91,13 @@ { "cell_type": "code", "execution_count": 2, - "id": "7ab805d8", + "id": "8f1a1a09", "metadata": { "execution": { - "iopub.execute_input": "2026-06-29T19:35:49.825583Z", - "iopub.status.busy": "2026-06-29T19:35:49.825515Z", - "iopub.status.idle": "2026-06-29T19:36:00.382823Z", - "shell.execute_reply": "2026-06-29T19:36:00.382407Z" + "iopub.execute_input": "2026-06-29T19:55:03.880293Z", + "iopub.status.busy": "2026-06-29T19:55:03.880225Z", + "iopub.status.idle": "2026-06-29T19:55:14.585293Z", + "shell.execute_reply": "2026-06-29T19:55:14.584897Z" } }, "outputs": [ @@ -119,14 +119,14 @@ "Total cost o.f. model formulation ****\n", "Investment elec model formulation ****\n", "Period 2030, Scenario sc01, Stage st1\n", - "Generation oper o.f. model formulation ****\n", - "Investment & operation var constraints ****\n" + "Generation oper o.f. model formulation ****\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ + "Investment & operation var constraints ****\n", "Inertia, oper resr, demand constraints ****\n", "Storage scheduling constraints ****\n", "Unit commitment constraints ****\n", @@ -147,7 +147,7 @@ "output_type": "stream", "text": [ "Termination condition: optimal\n", - " Total system cost [MEUR] 159.21117655177736 Constraints 41136 Variables 50966 Seconds 3\n", + " Total system cost [MEUR] 159.21117655177687 Constraints 41136 Variables 50966 Seconds 3\n", "***** Period: 2030, Scenario: sc01, Stage: st1 ******\n", " Total generation investment cost [MEUR] 0\n", " Total generation retirement cost [MEUR] 0\n", @@ -155,10 +155,10 @@ " Total network investment cost [MEUR] 4.041225328215885\n", " Total H2 pipe investment cost [MEUR] 0.0\n", " Total heat pipe investment cost [MEUR] 0.0\n", - " Total generation operation cost [MEUR] 155.16550622161148\n", - " Total consumption operation cost [MEUR] 0.0028532975065870933\n", + " Total generation operation cost [MEUR] 155.16550622161094\n", + " Total consumption operation cost [MEUR] 0.002853297506587079\n", " Total emission cost [MEUR] 0.0\n", - " Total network losses penalty cost [MEUR] 0.0015917044432770533\n", + " Total network losses penalty cost [MEUR] 0.0015917044432770529\n", " Total reliability electr cost [MEUR] 0.0\n", "Writing investment results ... 0 s\n", "Writing cost summary results ... 0 s\n", @@ -186,22 +186,28 @@ "name": "stdout", "output_type": "stream", "text": [ - "Setting up input data ... 0 s\n", + "Setting up input data ... 0 s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "Setting up variables ... 0 s\n", "Total cost o.f. model formulation ****\n", "Investment elec model formulation ****\n", "Period 2030, Scenario sc01, Stage st1\n", - "Generation oper o.f. model formulation ****\n" + "Generation oper o.f. model formulation ****\n", + "Investment & operation var constraints ****\n", + "Inertia, oper resr, demand constraints ****\n", + "Storage scheduling constraints ****\n", + "Unit commitment constraints ****\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Investment & operation var constraints ****\n", - "Inertia, oper resr, demand constraints ****\n", - "Storage scheduling constraints ****\n", - "Unit commitment constraints ****\n", "Ramp and min up/down time constraints ****\n", "Network switching model constraints ****\n", "Network operation model constraints ****\n" @@ -224,11 +230,11 @@ " Total generation investment cost [MEUR] 0\n", " Total generation retirement cost [MEUR] 0\n", " Total reservoir investment cost [MEUR] 0.0\n", - " Total network investment cost [MEUR] 5.3371090320017105\n", + " Total network investment cost [MEUR] 5.337109032001712\n", " Total H2 pipe investment cost [MEUR] 0.0\n", " Total heat pipe investment cost [MEUR] 0.0\n", - " Total generation operation cost [MEUR] 193.8862041750987\n", - " Total consumption operation cost [MEUR] 0.0028444742272815595\n", + " Total generation operation cost [MEUR] 193.88620417509864\n", + " Total consumption operation cost [MEUR] 0.0028444742272815526\n", " Total emission cost [MEUR] 0.0\n", " Total network losses penalty cost [MEUR] 0.001749808215068684\n", " Total reliability electr cost [MEUR] 0.0\n", @@ -270,13 +276,13 @@ { "cell_type": "code", "execution_count": 3, - "id": "3380edf2", + "id": "878551cd", "metadata": { "execution": { - "iopub.execute_input": "2026-06-29T19:36:00.383868Z", - "iopub.status.busy": "2026-06-29T19:36:00.383792Z", - "iopub.status.idle": "2026-06-29T19:36:00.387908Z", - "shell.execute_reply": "2026-06-29T19:36:00.387482Z" + "iopub.execute_input": "2026-06-29T19:55:14.586290Z", + "iopub.status.busy": "2026-06-29T19:55:14.586217Z", + "iopub.status.idle": "2026-06-29T19:55:14.590666Z", + "shell.execute_reply": "2026-06-29T19:55:14.590280Z" } }, "outputs": [ @@ -340,7 +346,7 @@ }, { "cell_type": "markdown", - "id": "b52a6101", + "id": "ee011979", "metadata": {}, "source": [ "## What just happened\n", @@ -350,7 +356,7 @@ }, { "cell_type": "markdown", - "id": "411a6fd5", + "id": "95576d5e", "metadata": {}, "source": [ "## Run the sweep in parallel\n", @@ -363,13 +369,13 @@ { "cell_type": "code", "execution_count": 4, - "id": "dc68a8d1", + "id": "5c9590fb", "metadata": { "execution": { - "iopub.execute_input": "2026-06-29T19:36:00.388853Z", - "iopub.status.busy": "2026-06-29T19:36:00.388796Z", - "iopub.status.idle": "2026-06-29T19:36:06.364709Z", - "shell.execute_reply": "2026-06-29T19:36:06.364253Z" + "iopub.execute_input": "2026-06-29T19:55:14.591761Z", + "iopub.status.busy": "2026-06-29T19:55:14.591708Z", + "iopub.status.idle": "2026-06-29T19:55:20.973568Z", + "shell.execute_reply": "2026-06-29T19:55:20.973070Z" } }, "outputs": [ @@ -433,26 +439,26 @@ " RHS [1e-03, 5e+02]\n", "Presolving model\n", "36761 rows, 45853 cols, 138280 nonzeros 0s\n", - "28396 rows, 37478 cols, 126116 nonzeros 0s\n", + "28396 rows, 37478 cols, 126109 nonzeros 0s\n", "Dependent equations search running on 5389 equations with time limit of 1000.00s\n", "Dependent equations search removed 0 rows and 0 nonzeros in 0.00s (limit = 1000.00s)\n", - "26482 rows, 34839 cols, 131299 nonzeros 0s\n", - "Presolve reductions: rows 26482(-14654); columns 34839(-22677); nonzeros 131299(-35398) \n", + "26482 rows, 34839 cols, 131292 nonzeros 0s\n", + "Presolve reductions: rows 26482(-14654); columns 34839(-22677); nonzeros 131292(-35405) \n", "Solving the presolved LP\n", "Using dual simplex solver\n", " Iteration Objective Infeasibilities num(sum)\n", " 0 0.0000000000e+00 Ph1: 0(0) 0.1s\n", - " 17019 1.9922790749e+02 Pr: 0(0); Du: 0(7.16127e-13) 1.6s\n", - " 17019 1.9922790749e+02 Pr: 0(0); Du: 0(7.16127e-13) 1.6s\n", + " 17500 1.9922790749e+02 Pr: 0(0) 1.9s\n", + " 17500 1.9922790749e+02 Pr: 0(0) 1.9s\n", "\n", "Performed postsolve\n", "Solving the original LP from the solution after postsolve\n", "\n", "Model status : Optimal\n", - "Simplex iterations: 17019\n", + "Simplex iterations: 17500\n", "Objective value : 1.9922790749e+02\n", - "P-D objective error : 2.5614385900e-15\n", - "HiGHS run time : 1.64\n" + "P-D objective error : 3.9844600289e-15\n", + "HiGHS run time : 1.91\n" ] }, { @@ -467,26 +473,26 @@ " RHS [9e-04, 5e+02]\n", "Presolving model\n", "36762 rows, 45854 cols, 138283 nonzeros 0s\n", - "28394 rows, 37474 cols, 126094 nonzeros 0s\n", + "28394 rows, 37474 cols, 126223 nonzeros 0s\n", "Dependent equations search running on 5388 equations with time limit of 1000.00s\n", "Dependent equations search removed 0 rows and 0 nonzeros in 0.00s (limit = 1000.00s)\n", - "26479 rows, 34834 cols, 131282 nonzeros 0s\n", - "Presolve reductions: rows 26479(-14657); columns 34834(-22682); nonzeros 131282(-35415) \n", + "26479 rows, 34834 cols, 131411 nonzeros 0s\n", + "Presolve reductions: rows 26479(-14657); columns 34834(-22682); nonzeros 131411(-35286) \n", "Solving the presolved LP\n", "Using dual simplex solver\n", " Iteration Objective Infeasibilities num(sum)\n", " 0 0.0000000000e+00 Ph1: 0(0) 0.1s\n", - " 17066 1.5921117655e+02 Pr: 0(0) 2.0s\n", - " 17066 1.5921117655e+02 Pr: 0(0) 2.0s\n", + " 17454 1.5921117655e+02 Pr: 0(0) 2.3s\n", + " 17454 1.5921117655e+02 Pr: 0(0) 2.3s\n", "\n", "Performed postsolve\n", "Solving the original LP from the solution after postsolve\n", "\n", "Model status : Optimal\n", - "Simplex iterations: 17066\n", + "Simplex iterations: 17454\n", "Objective value : 1.5921117655e+02\n", - "P-D objective error : 9.6986522634e-15\n", - "HiGHS run time : 1.99\n" + "P-D objective error : 3.7370953676e-15\n", + "HiGHS run time : 2.36\n" ] }, { @@ -494,18 +500,18 @@ "output_type": "stream", "text": [ "Termination condition: optimal\n", - " Total system cost [MEUR] 159.21117655177747 Constraints 41136 Variables 50966 Seconds 3\n", + " Total system cost [MEUR] 159.2111765517768 Constraints 41136 Variables 50966 Seconds 4\n", "***** Period: 2030, Scenario: sc01, Stage: st1 ******\n", " Total generation investment cost [MEUR] 0\n", " Total generation retirement cost [MEUR] 0\n", " Total reservoir investment cost [MEUR] 0.0\n", - " Total network investment cost [MEUR] 4.041225328215885\n", + " Total network investment cost [MEUR] 4.041225328215886\n", " Total H2 pipe investment cost [MEUR] 0.0\n", " Total heat pipe investment cost [MEUR] 0.0\n", - " Total generation operation cost [MEUR] 155.16550622161174\n", - " Total consumption operation cost [MEUR] 0.0028532975065870907\n", + " Total generation operation cost [MEUR] 155.16550622161085\n", + " Total consumption operation cost [MEUR] 0.002853297506587075\n", " Total emission cost [MEUR] 0.0\n", - " Total network losses penalty cost [MEUR] 0.001591704443277054\n", + " Total network losses penalty cost [MEUR] 0.0015917044432770529\n", " Total reliability electr cost [MEUR] 0.0\n", "Writing investment results ... 0 s\n", "Writing cost summary results ... 0 s\n", @@ -513,7 +519,7 @@ "Writing elect network summary results ... 0 s\n", "Writing economic results ... 0 s\n", "Termination condition: optimal\n", - " Total system cost [MEUR] 199.22790748954313 Constraints 41136 Variables 50966 Seconds 3\n", + " Total system cost [MEUR] 199.22790748954316 Constraints 41136 Variables 50966 Seconds 3\n", "***** Period: 2030, Scenario: sc01, Stage: st1 ******\n", " Total generation investment cost [MEUR] 0\n", " Total generation retirement cost [MEUR] 0\n", @@ -521,8 +527,8 @@ " Total network investment cost [MEUR] 5.337109032001712\n", " Total H2 pipe investment cost [MEUR] 0.0\n", " Total heat pipe investment cost [MEUR] 0.0\n", - " Total generation operation cost [MEUR] 193.8862041750986\n", - " Total consumption operation cost [MEUR] 0.0028444742272815513\n", + " Total generation operation cost [MEUR] 193.88620417509864\n", + " Total consumption operation cost [MEUR] 0.0028444742272815526\n", " Total emission cost [MEUR] 0.0\n", " Total network losses penalty cost [MEUR] 0.001749808215068684\n", " Total reliability electr cost [MEUR] 0.0\n", @@ -545,13 +551,13 @@ { "cell_type": "code", "execution_count": 5, - "id": "c3c191e3", + "id": "860321cf", "metadata": { "execution": { - "iopub.execute_input": "2026-06-29T19:36:06.365895Z", - "iopub.status.busy": "2026-06-29T19:36:06.365818Z", - "iopub.status.idle": "2026-06-29T19:36:06.369749Z", - "shell.execute_reply": "2026-06-29T19:36:06.369416Z" + "iopub.execute_input": "2026-06-29T19:55:20.974686Z", + "iopub.status.busy": "2026-06-29T19:55:20.974612Z", + "iopub.status.idle": "2026-06-29T19:55:20.978176Z", + "shell.execute_reply": "2026-06-29T19:55:20.977912Z" } }, "outputs": [ @@ -615,7 +621,7 @@ }, { "cell_type": "markdown", - "id": "7786396c", + "id": "4d94236a", "metadata": {}, "source": [ "`backend=\"joblib\"` works the same way (it needs `pip install joblib`). On a real sweep with many cases, raise `n_workers` to the number of cores you want to use." @@ -623,26 +629,26 @@ }, { "cell_type": "markdown", - "id": "302c1023", + "id": "1f9da42e", "metadata": {}, "source": [ "## Collect every case's results into one table\n", "\n", "So far we only compared the total cost. To compare the full results across cases, pass `aggregate_to` a folder. After the sweep, openTEPES stacks each result table across all cases into one long table, `oT_Sweep_.csv`, with a leading `case` column.\n", "\n", - "This reads the per-case results from disk, so we turn result writing on with `pIndOutputResults=\"Yes\"`." + "This reads the per-case results from disk, so we turn result writing on with `pIndOutputResults=\"Yes\"`. It also composes with the parallel backend, so we run it with `multiprocessing` here." ] }, { "cell_type": "code", "execution_count": 6, - "id": "e81674f8", + "id": "78935c7e", "metadata": { "execution": { - "iopub.execute_input": "2026-06-29T19:36:06.370735Z", - "iopub.status.busy": "2026-06-29T19:36:06.370674Z", - "iopub.status.idle": "2026-06-29T19:36:18.407017Z", - "shell.execute_reply": "2026-06-29T19:36:18.406549Z" + "iopub.execute_input": "2026-06-29T19:55:20.979256Z", + "iopub.status.busy": "2026-06-29T19:55:20.979190Z", + "iopub.status.idle": "2026-06-29T19:55:28.064609Z", + "shell.execute_reply": "2026-06-29T19:55:28.064116Z" } }, "outputs": [ @@ -652,20 +658,8 @@ "text": [ "Input data ****\n", "Reading the CSV files ... 0 s\n", - "Reading input data ... 0 s\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Setting up input data ... 1 s\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "Reading input data ... 0 s\n", + "Setting up input data ... 1 s\n", "Setting up variables ... 0 s\n", "Total cost o.f. model formulation ****\n", "Investment elec model formulation ****\n", @@ -674,23 +668,108 @@ "Investment & operation var constraints ****\n", "Inertia, oper resr, demand constraints ****\n", "Storage scheduling constraints ****\n", - "Unit commitment constraints ****\n" + "Unit commitment constraints ****\n", + "Ramp and min up/down time constraints ****\n", + "Network switching model constraints ****\n", + "Network operation model constraints ****\n", + "Problem solving #### 1\n", + "Input data ****\n", + "Reading the CSV files ... 0 s\n", + "Reading input data ... 0 s\n", + "Setting up input data ... 1 s\n", + "Setting up variables ... 0 s\n", + "Total cost o.f. model formulation ****\n", + "Investment elec model formulation ****\n", + "Period 2030, Scenario sc01, Stage st1\n", + "Generation oper o.f. model formulation ****\n", + "Investment & operation var constraints ****\n", + "Inertia, oper resr, demand constraints ****\n", + "Storage scheduling constraints ****\n", + "Unit commitment constraints ****\n", + "Ramp and min up/down time constraints ****\n", + "Network switching model constraints ****\n", + "Network operation model constraints ****\n", + "Problem solving #### 1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Ramp and min up/down time constraints ****\n", - "Network switching model constraints ****\n", - "Network operation model constraints ****\n" + "Running HiGHS 1.14.0 (git hash: 7df0786): Copyright (c) 2026 under MIT licence terms\n", + "Running HiGHS 1.14.0 (git hash: 7df0786): Copyright (c) 2026 under MIT licence terms\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Problem solving #### 1\n" + "LP has 41136 rows; 57516 cols; 166697 nonzeros\n", + "Coefficient ranges:\n", + " Matrix [1e-04, 2e+02]\n", + " Cost [1e+00, 1e+00]\n", + " Bound [1e-03, 1e+03]\n", + " RHS [1e-03, 5e+02]\n", + "Presolving model\n", + "36761 rows, 45853 cols, 138280 nonzeros 0s\n", + "28396 rows, 37478 cols, 126229 nonzeros 0s\n", + "Dependent equations search running on 5389 equations with time limit of 1000.00s\n", + "Dependent equations search removed 0 rows and 0 nonzeros in 0.00s (limit = 1000.00s)\n", + "26482 rows, 34839 cols, 131412 nonzeros 0s\n", + "Presolve reductions: rows 26482(-14654); columns 34839(-22677); nonzeros 131412(-35285) \n", + "Solving the presolved LP\n", + "Using dual simplex solver\n", + " Iteration Objective Infeasibilities num(sum)\n", + " 0 0.0000000000e+00 Ph1: 0(0) 0.1s\n", + " 17378 1.9922790749e+02 Pr: 0(0) 1.9s\n", + " 17378 1.9922790749e+02 Pr: 0(0) 1.9s\n", + "\n", + "Performed postsolve\n", + "Solving the original LP from the solution after postsolve\n", + "\n", + "Model status : Optimal\n", + "Simplex iterations: 17378\n", + "Objective value : 1.9922790749e+02\n", + "P-D objective error : 2.7748918059e-15\n", + "HiGHS run time : 1.89\n", + "LP has 41136 rows; 57516 cols; 166697 nonzeros\n", + "Coefficient ranges:\n", + " Matrix [1e-04, 2e+02]\n", + " Cost [1e+00, 1e+00]\n", + " Bound [9e-04, 1e+03]\n", + " RHS [9e-04, 5e+02]\n", + "Presolving model\n", + "36762 rows, 45854 cols, 138283 nonzeros 0s\n", + "28394 rows, 37474 cols, 126222 nonzeros 0s\n", + "Dependent equations search running on 5388 equations with time limit of 1000.00s\n", + "Dependent equations search removed 0 rows and 0 nonzeros in 0.00s (limit = 1000.00s)\n", + "26479 rows, 34834 cols, 131410 nonzeros 0s\n", + "Presolve reductions: rows 26479(-14657); columns 34834(-22682); nonzeros 131410(-35287) \n", + "Solving the presolved LP\n", + "Using dual simplex solver\n", + " Iteration Objective Infeasibilities num(sum)\n", + " 0 0.0000000000e+00 Ph1: 0(0) 0.1s\n", + " 16810 1.5921117655e+02 Pr: 0(0) 2.0s\n", + " 16810 1.5921117655e+02 Pr: 0(0) 2.0s\n", + "\n", + "Performed postsolve\n", + "Solving the original LP from the solution after postsolve\n", + "\n", + "Model status : Optimal\n", + "Simplex iterations: 16810\n", + "Objective value : 1.5921117655e+02\n", + "P-D objective error : 4.3599445955e-15\n", + "HiGHS run time : 2.05\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/private/tmp/claude-501/-Users-philias-ai-research-repos-openTEPES-tutorial/8f6d4ac5-9ff1-45bc-8a3c-5cc562abe3f1/scratchpad/venv312/lib/python3.12/site-packages/altair/utils/core.py:264: UserWarning: I don't know how to infer vegalite type from 'empty'. Defaulting to nominal.\n", + " warnings.warn(\n", + "/private/tmp/claude-501/-Users-philias-ai-research-repos-openTEPES-tutorial/8f6d4ac5-9ff1-45bc-8a3c-5cc562abe3f1/scratchpad/venv312/lib/python3.12/site-packages/altair/utils/core.py:264: UserWarning: I don't know how to infer vegalite type from 'empty'. Defaulting to nominal.\n", + " warnings.warn(\n" ] }, { @@ -698,166 +777,55 @@ "output_type": "stream", "text": [ "Termination condition: optimal\n", - " Total system cost [MEUR] 159.21117655177736 Constraints 41136 Variables 50966 Seconds 3\n", + " Total system cost [MEUR] 159.21117655177702 Constraints 41136 Variables 50966 Seconds 4\n", "***** Period: 2030, Scenario: sc01, Stage: st1 ******\n", " Total generation investment cost [MEUR] 0\n", " Total generation retirement cost [MEUR] 0\n", " Total reservoir investment cost [MEUR] 0.0\n", - " Total network investment cost [MEUR] 4.041225328215885\n", + " Total network investment cost [MEUR] 4.0412253282158845\n", " Total H2 pipe investment cost [MEUR] 0.0\n", " Total heat pipe investment cost [MEUR] 0.0\n", - " Total generation operation cost [MEUR] 155.16550622161148\n", - " Total consumption operation cost [MEUR] 0.0028532975065870933\n", + " Total generation operation cost [MEUR] 155.1655062216113\n", + " Total consumption operation cost [MEUR] 0.002853297506587099\n", " Total emission cost [MEUR] 0.0\n", - " Total network losses penalty cost [MEUR] 0.0015917044432770533\n", + " Total network losses penalty cost [MEUR] 0.001591704443277053\n", " Total reliability electr cost [MEUR] 0.0\n", "Writing investment results ... 0 s\n", - "Writing cost summary results ... 0 s\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "Writing cost summary results ... 0 s\n", "Writing KPI summary results ... 0 s\n", "Writing elect network summary results ... 0 s\n", "Writing reliability indexes ... 0 s\n", - "Writing flexibility results ... 0 s\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/private/tmp/claude-501/-Users-philias-ai-research-repos-openTEPES-tutorial/8f6d4ac5-9ff1-45bc-8a3c-5cc562abe3f1/scratchpad/venv312/lib/python3.12/site-packages/altair/utils/core.py:264: UserWarning: I don't know how to infer vegalite type from 'empty'. Defaulting to nominal.\n", - " warnings.warn(\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "Writing flexibility results ... 0 s\n", "Writing generation operation results ... 0 s\n", "Writing ESS operation results ... 0 s\n", - "Writing elect netwk operation results ... 0 s\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Writing marginal information results ... 0 s\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "Writing elect netwk operation results ... 0 s\n", + "Writing marginal information results ... 0 s\n", "Writing economic results ... 0 s\n", "Plotting electricity network maps ... 0 s\n", - "Input data ****\n", - "Reading the CSV files ... 0 s\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Reading input data ... 0 s\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Setting up input data ... 1 s\n", - "Setting up variables ... 0 s\n", - "Total cost o.f. model formulation ****\n", - "Investment elec model formulation ****\n", - "Period 2030, Scenario sc01, Stage st1\n", - "Generation oper o.f. model formulation ****\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Investment & operation var constraints ****\n", - "Inertia, oper resr, demand constraints ****\n", - "Storage scheduling constraints ****\n", - "Unit commitment constraints ****\n", - "Ramp and min up/down time constraints ****\n", - "Network switching model constraints ****\n", - "Network operation model constraints ****\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Problem solving #### 1\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ "Termination condition: optimal\n", - " Total system cost [MEUR] 199.22790748954316 Constraints 41136 Variables 50966 Seconds 3\n", + " Total system cost [MEUR] 199.22790748954318 Constraints 41136 Variables 50966 Seconds 3\n", "***** Period: 2030, Scenario: sc01, Stage: st1 ******\n", " Total generation investment cost [MEUR] 0\n", " Total generation retirement cost [MEUR] 0\n", " Total reservoir investment cost [MEUR] 0.0\n", - " Total network investment cost [MEUR] 5.3371090320017105\n", + " Total network investment cost [MEUR] 5.337109032001712\n", " Total H2 pipe investment cost [MEUR] 0.0\n", " Total heat pipe investment cost [MEUR] 0.0\n", - " Total generation operation cost [MEUR] 193.8862041750987\n", - " Total consumption operation cost [MEUR] 0.0028444742272815595\n", + " Total generation operation cost [MEUR] 193.88620417509867\n", + " Total consumption operation cost [MEUR] 0.0028444742272815543\n", " Total emission cost [MEUR] 0.0\n", " Total network losses penalty cost [MEUR] 0.001749808215068684\n", " Total reliability electr cost [MEUR] 0.0\n", "Writing investment results ... 0 s\n", - "Writing cost summary results ... 0 s\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "Writing cost summary results ... 0 s\n", "Writing KPI summary results ... 0 s\n", "Writing elect network summary results ... 0 s\n", "Writing reliability indexes ... 0 s\n", - "Writing flexibility results ... 0 s\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/private/tmp/claude-501/-Users-philias-ai-research-repos-openTEPES-tutorial/8f6d4ac5-9ff1-45bc-8a3c-5cc562abe3f1/scratchpad/venv312/lib/python3.12/site-packages/altair/utils/core.py:264: UserWarning: I don't know how to infer vegalite type from 'empty'. Defaulting to nominal.\n", - " warnings.warn(\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "Writing flexibility results ... 0 s\n", "Writing generation operation results ... 0 s\n", "Writing ESS operation results ... 0 s\n", - "Writing elect netwk operation results ... 0 s\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Writing marginal information results ... 0 s\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "Writing elect netwk operation results ... 0 s\n", + "Writing marginal information results ... 0 s\n", "Writing economic results ... 0 s\n", "Plotting electricity network maps ... 0 s\n" ] @@ -866,7 +834,7 @@ "source": [ "records = openTEPES_Runner.run(\n", " cases, \"appsi_highs\",\n", - " mode=\"pre-build\", backend=\"serial\",\n", + " mode=\"pre-build\", backend=\"multiprocessing\", n_workers=2,\n", " pIndOutputResults=\"Yes\", pIndLogConsole=\"No\",\n", " aggregate_to=\"sweepA_merged\",\n", ")" @@ -874,7 +842,7 @@ }, { "cell_type": "markdown", - "id": "35db0846", + "id": "8e1cda92", "metadata": {}, "source": [ "Each `oT_Sweep_*.csv` in `sweepA_merged/` holds every case's rows for one result, told apart by the `case` column. For example, the total generation per technology in each case:" @@ -883,13 +851,13 @@ { "cell_type": "code", "execution_count": 7, - "id": "4db52e7d", + "id": "2b3533a7", "metadata": { "execution": { - "iopub.execute_input": "2026-06-29T19:36:18.408156Z", - "iopub.status.busy": "2026-06-29T19:36:18.408081Z", - "iopub.status.idle": "2026-06-29T19:36:18.412577Z", - "shell.execute_reply": "2026-06-29T19:36:18.412246Z" + "iopub.execute_input": "2026-06-29T19:55:28.065839Z", + "iopub.status.busy": "2026-06-29T19:55:28.065758Z", + "iopub.status.idle": "2026-06-29T19:55:28.070622Z", + "shell.execute_reply": "2026-06-29T19:55:28.070295Z" } }, "outputs": [ @@ -974,7 +942,7 @@ }, { "cell_type": "markdown", - "id": "8c8c33d1", + "id": "9fba8b9c", "metadata": {}, "source": [ "When your cases share most of their inputs, Mode A re-reads the same data for each one. The next notebook, [Mode B](5.2-Sweep-Mode-B-InMemory.ipynb), avoids that."